#!/usr/bin/env python3

import argparse
import csv
import glob
import json
import os
import shutil
import sys
import tempfile

UNRELEASED = "UNRELEASED"


def find_root():
    # expected path is in <top_dir>/packages/
    top_dir = os.environ.get("UACLIENT_TOP_D", None)
    if top_dir is None:
        top_dir = os.path.dirname(
            os.path.dirname(os.path.abspath(sys.argv[0])))
    if os.path.isfile(os.path.join(top_dir, 'setup.py')):
        return os.path.abspath(top_dir)
    raise OSError(
        "Unable to determine where your ubuntu-advantage-scripts topdir is."
        " set UACLIENT_TOP_D?")

if "avoid-pep8-E402-import-not-top-of-file":
    # Use the util functions from uaclient
    sys.path.insert(0, find_root())
    from uaclient import util
    from uaclient import version

DEBUILD_ARGS = ["-S", "-d"]


def get_release_suffix(release):
    """Given ubuntu release (xenial), return a suffix for package (~16.04.1)"""
    csv_path = "/usr/share/distro-info/ubuntu.csv"
    rels = {}
    # fields are version, codename, series, created, release, eol, eol-server
    if os.path.exists(csv_path):
        with open(csv_path, "r") as fp:
            # version has "16.04 LTS" or "16.10", so drop "LTS" portion.
            rels = {row['series']: row['version'].replace(' LTS', '')
                    for row in csv.DictReader(fp)}
    if release in rels:
        return "~%s.1" % rels[release]
    elif release != UNRELEASED:
        print("missing distro-info-data package, unable to give "
              "per-release suffix.\n")
    return ""


def run_helper(helper, args=None, strip=True):
    if args is None:
        args = []
    cmd = [os.path.join(find_root(), 'dev', helper)] + args
    (stdout, _stderr) = util.subp(cmd)
    if strip:
        stdout = stdout.strip()
    return stdout


def write_debian_folder(root, templ_data):
    """Create a debian package directory with all rendered template files."""
    print("Creating a debian/ folder in %r" % (root))

    # Write out the control file template
    reqs_output = run_helper(
        'read-dependencies', args=['--python-version', '3', '--system-pkg-names'])
    reqs = reqs_output.splitlines()
    test_reqs = run_helper(
        'read-dependencies',
        ['--requirements-file', 'test-requirements.txt',
         '--system-pkg-names', '--python-version', '3']).splitlines()

    requires = []
    # We consolidate all deps as Build-Depends as our package build runs all
    # tests so we need all runtime dependencies anyway.
    requires.extend(['python3'] + reqs + test_reqs)
    templ_data['%BUILD_DEPS%'] = ','.join(requires)

    # Iterate over any .in template files and rendir into deb_dir
    template_files  = glob.glob(os.path.join(root, 'dev') + '/*.in')
    deb_dir = os.path.join(root, 'debian')
    subcmds = ['s/%s/%s/' % (k, v) for k, v in templ_data.items()]
    for tmpl_file in template_files:
        replace_cmd = ['sed', '-e', '; '.join(subcmds), tmpl_file]
        out, _ = util.subp(replace_cmd)
        tmpl_filename = os.path.basename(tmpl_file).rstrip('.in')
        util.write_file(os.path.join(deb_dir, tmpl_filename), out)


def get_parser():
    """Setup and return an argument parser for bdeb tool."""
    parser = argparse.ArgumentParser()
    parser.add_argument("-v", "--verbose", dest="verbose",
                        help=("run verbosely"
                              " (default: %(default)s)"),
                        default=False,
                        action='store_true')
    parser.add_argument("--cloud-utils", dest="cloud_utils",
                        help=("depend on cloud-utils package"
                              " (default: %(default)s)"),
                        default=False,
                        action='store_true')

    parser.add_argument("--init-system", dest="init_system",
                        help=("build deb with INIT_SYSTEM=xxx"
                              " (default: %(default)s"),
                        default=os.environ.get("INIT_SYSTEM", "systemd"))

    parser.add_argument("--series", dest="series",
                        help=("build with changelog referencing SERIES name"),
                        choices=['trusty', 'xenial', 'bionic', 'cosmic', 'disco'],
                        default=UNRELEASED)

    for ent in DEBUILD_ARGS:
        parser.add_argument(ent, dest="debuild_args", action='append_const',
                            const=ent, default=[],
                            help=("pass through '%s' to debuild" % ent))

    parser.add_argument("--sign", default=False, action='store_true',
                        help="sign result. do not pass -us -uc to debuild")

    parser.add_argument("--signuser", default=False, action='store',
                        help="user to sign, see man dpkg-genchanges")
    return parser


def main():
    parser = get_parser()
    args = parser.parse_args()

    if not args.sign:
        args.debuild_args.extend(['-us', '-uc'])

    if args.signuser:
        args.debuild_args.extend(['-e%s' % args.signuser])

    os.environ['INIT_SYSTEM'] = args.init_system

    capture = True
    if args.verbose:
        capture = False

    ver = version.get_version()
    # templ_data used in sed -e cmd
    templ_data = {
        '%DEBIAN_SERIES%': args.series,
        '%VERSION_LONG%': ver,
        '%PACKAGE_SUFFIX%': get_release_suffix(args.series)}

    tdir = tempfile.mkdtemp(prefix='uaclient-')

    # output like 18.1-29-g36e92d3

    # This is really only a temporary archive
    # since we will extract it then add in the debian
    # folder, then re-archive it for debian happiness
    tarball = "ubuntu-advantage-tools_%s.orig.tar.gz" % ver
    tarball_fp = os.path.join(tdir, tarball)
    path = None
    for pd in ("./", "../", "../dl/"):
        if os.path.exists(pd + tarball):
            path = pd + tarball
            print("Using existing tarball %s" % path)
            shutil.copy(path, tarball_fp)
            break
    if path is None:
        print('Creating a temp tarball: %s' % tarball_fp)
        run_helper('make-tarball', ['--long', '--output=' + tarball_fp])

    print("Extracting temporary tarball %r" % (tarball))
    cmd = ['tar', '-xvzf', tarball_fp, '-C', tdir]
    util.subp(cmd, capture=capture)

    xdir = os.path.join(tdir, "ubuntu-advantage-tools-%s" % ver)

    write_debian_folder(xdir, templ_data)

    print("Running 'debuild %s' in %r" % (' '.join(args.debuild_args),
                                          xdir))

    cwd = os.getcwd()
    os.chdir(xdir)
    cmd = ['debuild', '--preserve-envvar', 'INIT_SYSTEM']
    if args.debuild_args:
        cmd.extend(args.debuild_args)
    util.subp(cmd, capture=capture)
    os.chdir(cwd)

    link_fn = os.path.join(cwd, 'ubuntu-advantage-tools_all.deb')
    link_dsc = os.path.join(cwd, 'ubuntu_advantage_tools.dsc')
    for base_fn in os.listdir(os.path.join(tdir)):
        full_fn = os.path.join(tdir, base_fn)
        if not os.path.isfile(full_fn):
            continue
        shutil.move(full_fn, base_fn)
        print("Wrote %r" % (base_fn))
        if base_fn.endswith('_all.deb'):
            # Add in the local link
            util.del_file(link_fn)
            shutil.copy(base_fn, link_fn)
            print("Linked %r to %r" % (base_fn,
                                       os.path.basename(link_fn)))
        if base_fn.endswith('.dsc'):
            util.del_file(link_dsc)
            os.symlink(base_fn, link_dsc)
            print("Linked %r to %r" % (base_fn,
                                       os.path.basename(link_dsc)))
    if os.path.exists(tdir):
        shutil.rmtree(tdir)

    return 0


if __name__ == '__main__':
    sys.exit(main())
