#!/usr/bin/env python
# encoding: utf-8
"""Helps with command line commands."""

import os
import shutil
import sys
import json
import click
import yaml
import loaih
import loaih.build


@click.group()
def cli():
    """Helps with command line commands."""


@cli.command()
@click.option('-j', '--json', 'jsonout', default=False, is_flag=True, help="Output format in json.")
@click.option('--default-to-current', '-d', is_flag=True, default=False, help="If no versions are found, default to current one (for daily builds). Default: do not default to current.")
@click.argument('query')
def getversion(query, jsonout, default_to_current):
    """Get download information for named or numbered versions."""

    batchlist = []
    queries = []
    if ',' in query:
        queries.extend(query.split(','))
    else:
        queries.append(query)

    for singlequery in queries:
        elem = loaih.Solver.parse(singlequery, default_to_current)
        if elem.version not in { None, "" }:
            batchlist.append(elem)

    if len(batchlist) > 0:
        if jsonout:
            click.echo(json.dumps([x.to_dict() for x in batchlist ]))
        else:
            for value in batchlist:
                click.echo(value)


@cli.command()
@click.option('-a', '--arch', 'arch', default='x86_64',
    type=click.Choice(['x86', 'x86_64', 'all'], case_sensitive=False), help="Build the AppImage for a specific architecture. Default: x86_64")
@click.option('--check', '-c', is_flag=True, default=False, help="Checks in the repository path if the queried version is existent. Default: do not check")
@click.option('--checksums', '-e', is_flag=True, default=False, help="Create checksums for each created file (AppImage). Default: do not create checksums.")
@click.option('--keep-downloads', '-k', 'keep', is_flag=True, default=False, help="Keep the downloads folder after building the AppImage. Default: do not keep.")
@click.option('--languages', '-l', 'language', default='basic', type=str, help="Languages to be included. Options: basic, standard, full, a language string (e.g. 'it') or a list of languages comma separated (e.g.: 'en-US,en-GB,it'). Default: basic")
@click.option('--offline-help', '-o', 'offline', is_flag=True, default=False, help="Include the offline help pages for the chosen languages. Default: no offline help")
@click.option('--portable', '-p', 'portable', is_flag=True, default=False, help="Create a portable version of the AppImage or not. Default: no portable")
@click.option('--sign', '-s', is_flag=True, default=False, help="Sign the build with your default GPG key. Default: do not sign")
@click.option('--updatable', '-u', is_flag=True, default=False, help="Create an updatable AppImage (compatible with zsync2). Default: not updatable")
@click.option('--download-path', '-d', default='./downloads', type=str, help="Path to the download folder. Default: ./downloads")
@click.option('--repo-path', '-r', default='.', type=str, help="Path to the final storage of the AppImage. Default: current directory")
@click.argument('query')
def build(arch, language, offline, portable, updatable, download_path, repo_path, check, checksums, sign, keep, query):
    """Builds an Appimage with the provided options."""

    # Multiple query support
    queries = []
    if ',' in query:
        queries.extend(query.split(','))
    else:
        queries.append(query)

    # Parsing options
    arches = []
    if arch.lower() == 'all':
        # We need to build it twice.
        arches = ['x86', 'x86_64']
    else:
        arches = [arch.lower()]

    # Other more global variables
    repopath = os.path.abspath(repo_path)
    if not os.path.exists(repopath):
        os.makedirs(repopath, exist_ok=True)
    downloadpath = os.path.abspath(download_path)
    if not os.path.exists(downloadpath):
        os.makedirs(downloadpath, exist_ok=True)

    for myquery in queries:
        for appbuild in loaih.build.Collection(myquery, arches):
            # Configuration phase
            appbuild.tidy_folder = False
            appbuild.language = language
            appbuild.offline_help = offline
            appbuild.portable = portable
            appbuild.updatable = updatable
            appbuild.storage_path = repopath
            appbuild.download_path = downloadpath
            appbuild.sign = sign

            # Running phase
            appbuild.calculate()

            if check:
                appbuild.check()

            appbuild.download()
            appbuild.build()
            if checksums:
                appbuild.checksums()
            appbuild.publish()

            del appbuild

    if not keep:
        shutil.rmtree(downloadpath)


@cli.command()
@click.option("--verbose", '-v', is_flag=True, default=False, help="Show building phases.", show_default=True)
@click.argument("yamlfile")
def batch(yamlfile, verbose):
    """Builds a collection of AppImages based on YAML file."""
    # Defaults for a batch building is definitely more different than a
    # manual one. To reflect this behaviour, I decided to split the commands
    # between batch (bulk creation) and build (manual building).

    # Check if yamlfile exists.
    if not os.path.exists(os.path.abspath(yamlfile)):
        click.echo(f"YAML file {yamlfile} does not exists or is unreadable.")
        sys.exit(1)

    # This is a buildfile. So we have to load the file and pass the build
    # options ourselves.
    config = {}
    with open(os.path.abspath(yamlfile), 'r', encoding='utf-8') as file:
        config = yaml.safe_load(file)

    # Globals for yamlfile
    gvars = {}
    gvars['download_path'] = "/var/tmp/downloads"
    if 'download' in config['data'] and config['data']['download']:
        gvars['download_path'] = config['data']['download']

    gvars['force'] = False
    if 'force' in config['data'] and config['data']['force']:
        gvars['force'] = config['data']['force']

    gvars['storage_path'] = "/srv/http/appimage"
    if 'repo' in config['data'] and config['data']['repo']:
        gvars['storage_path'] = config['data']['repo']

    gvars['remoterepo'] = False
    gvars['remote_host'] = ''
    gvars['remote_path'] = "/srv/http/appimage"
    if 'http' in gvars['storage_path']:
        gvars['remoterepo'] = True
        gvars['remote_host'] = "ciccio.libreitalia.org"
        if 'remote_host' in config['data'] and config['data']['remote_host']:
            gvars['remote_host'] = config['data']['remote_host']

        if 'remote_path' in config['data'] and config['data']['remote_path']:
            gvars['remote_path'] = config['data']['remote_path']

    gvars['sign'] = False
    if 'sign' in config['data'] and config['data']['sign']:
        gvars['sign'] = True

    # With the config file, we ignore all the command line options and set
    # generic default.
    for cbuild in config['builds']:
        # Loop a run for each build.
        collection = loaih.build.Collection(cbuild['query'])

        for obj in collection:
            # Configuration phase
            obj.verbose = verbose
            obj.language = 'basic'
            if 'language' in cbuild and cbuild['language']:
                obj.language = cbuild['language']
            obj.offline_help = False
            if 'offline_help' in cbuild and cbuild['offline_help']:
                obj.offline_help = cbuild['offline_help']
            obj.portable = False
            if 'portable' in cbuild and cbuild['portable']:
                obj.portable = cbuild['portable']
            obj.updatable = True
            obj.storage_path = gvars['storage_path']
            obj.download_path = gvars['download_path']
            obj.remoterepo = gvars['remoterepo']
            obj.remote_host = gvars['remote_host']
            obj.remote_path = gvars['remote_path']
            obj.sign = gvars['sign']

            # Build phase
            obj.calculate()
            if not gvars['force']:
                obj.check()
            obj.download()
            obj.build()
            obj.checksums()
            if obj.remoterepo and obj.appnamedir:
                obj.generalize_and_link(obj.appnamedir)
            obj.publish()
            if not obj.remoterepo:
                obj.generalize_and_link()
            del obj

    # In case prerelease or daily branches are used, cleanup the download
    # folder after finishing the complete run (to make sure the next run
    # will redownload all the needed files and is indeed fresh).
    # we will swipe all the builds inside a collection to understand the files
    # to delete.
    for cbuild in config['builds']:
        # Loop a run for each build.
        for build in loaih.build.Collection(cbuild['query']):

            if build.version.branch in {'prerelease', 'daily'}:
                build.version.cleanup_downloads(gvars['download_path'], verbose)
