#!/usr/bin/python3

import argparse
import datetime
import logging
import os
import sys
import time
from pkg_resources import parse_version
from zipfile import is_zipfile

from keyman_config import KeymanApiUrl, __version__, secure_lookup
from keyman_config.uninstall_kmp import uninstall_kmp


def get_languages():
    import requests
    import requests_cache

    from keyman_config.get_kmp import keyman_cache_dir

    logging.info("Getting language list from search")
    api_url = KeymanApiUrl + "/search?q=l:*&platform=linux"
    logging.debug("At URL %s", api_url)
    cache_dir = keyman_cache_dir()
    current_dir = os.getcwd()
    expire_after = datetime.timedelta(days=7)
    if not os.path.isdir(cache_dir):
        os.makedirs(cache_dir)
    os.chdir(cache_dir)
    requests_cache.install_cache(cache_name='keyman_cache', backend='sqlite', expire_after=expire_after)
    now = time.ctime(int(time.time()))
    try:
        response = requests.get(api_url)
        logging.debug("Time: {0} / Used Cache: {1}".format(now, response.from_cache))
        os.chdir(current_dir)
        requests_cache.uninstall_cache()
        if response.status_code == 200:
            return response.json()
        else:
            return None
    except Exception:
        return None


def get_keyboard_list():
    languages = get_languages()
    keyboards = []
    if not languages:
        return []

    if "languages" in languages:
        for lang in languages["languages"]:
            if "keyboards" in lang:
                for kb in lang["keyboards"]:
                    kbnospace = kb.replace(" ", "%20")
                    if kbnospace not in keyboards:
                        keyboards.append(kbnospace)
    if keyboards:
        keyboards.sort()
    return keyboards


def write_kmpdirlist(kmpdirfile):
    try:
        with open(kmpdirfile, 'wt') as kmpdirlist:
            keyboards = get_keyboard_list()
            if keyboards:
                for kb in get_keyboard_list():
                    print(kb, file=kmpdirlist)
    except Exception as e:
        logging.warning('Exception %s writing %s %s', type(e), kmpdirfile, e.args)


def list_keyboards():
    from keyman_config.get_kmp import keyman_cache_dir
    kmpdirfile = os.path.join(keyman_cache_dir(), 'kmpdirlist')
    if not os.path.exists(kmpdirfile):
        write_kmpdirlist(kmpdirfile)
    else:
        logging.debug("kmpdirlist already exists")
        # file empty
        if os.path.getsize(kmpdirfile) == 0:
            write_kmpdirlist(kmpdirfile)


def main():
    parser = argparse.ArgumentParser(
      description='Install a Keyman keyboard package, either a local .kmp file or specify a ' +
      'keyboard id to download and install, optionally specifying a language for which to ' +
      'install the keyboard.',
      epilog='Example: km-package-install -s -p sil_el_ethiopian_latin --bcp47 ssy-latn')
    parser.add_argument('-s', '--shared', action='store_true', help='Install to shared area /usr/local')
    parser.add_argument('-f', '--file', metavar='KMPFILE', help='Keyman kmp file')
    parser.add_argument('-p', '--package', metavar='PACKAGE', help='Keyman package id')
    parser.add_argument('-l', '--bcp47', metavar='LANGTAG', help='bcp47 language tag')
    parser.add_argument('--version', action='version', version='%(prog)s version ' + __version__)
    parser.add_argument('-v', '--verbose', action='store_true', help='verbose logging')
    parser.add_argument('-vv', '--veryverbose', action='store_true', help='very verbose logging')

    args = parser.parse_args()
    if args.verbose:
        logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(message)s')
    elif args.veryverbose:
        logging.basicConfig(level=logging.DEBUG, format='%(levelname)s:%(message)s')
    else:
        logging.basicConfig(format='%(levelname)s:%(message)s')

    if args.package and args.file:
        parser.print_usage()
        logging.error(
          "km-package-install: error: too many arguments: either install a local kmp file or " +
          "specify a keyboard id to download and install.")
        sys.exit(2)

    from keyman_config.get_kmp import (get_keyboard_data, get_kmp,
                                       keyman_cache_dir)
    from keyman_config.install_kmp import (InstallError, InstallStatus,
                                           install_kmp)
    from keyman_config.list_installed_kmp import get_kmp_version_shared, get_kmp_version_user

    if os.path.exists(os.path.join(keyman_cache_dir(), 'kmpdirlist')):
        os.remove(os.path.join(keyman_cache_dir(), 'kmpdirlist'))

    def try_install_kmp(inputfile, arg, language=None, online=False, sharedarea=False):
        try:
            install_kmp(inputfile, online, sharedarea, language)
        except InstallError as e:
            if e.status == InstallStatus.Abort:
                logging.error("km-package-install: error: Failed to install %s", arg)
                logging.error(e.message)
                sys.exit(3)
            else:
                logging.warning(e.message)

    if args.file:
        name, ext = os.path.splitext(args.file)
        if ext != ".kmp" or not is_zipfile(args.file):
            logging.error("km-package-install: Input file %s is not a kmp file.", args.file)
            logging.error("km-package-install -f <kmpfile>")
            sys.exit(2)

        if not os.path.isfile(args.file):
            logging.error("km-package-install: Keyman kmp file %s not found.", args.file)
            logging.error("km-package-install -f <kmpfile>")
            sys.exit(2)
        try_install_kmp(args.file, "file " + args.file, args.bcp47, False, args.shared)
    elif args.package:
        if args.shared:
            if get_kmp_version_user(args.package):
                print("km-package-install: Warning: Keyboard %s is also installed for the current user."
                      % args.package)
            installed_kmp_v = get_kmp_version_shared(args.package)
        else:
            if get_kmp_version_shared(args.package):
                print("km-package-install: Warning: Keyboard %s is already installed in the shared area."
                      % args.package)
            installed_kmp_v = get_kmp_version_user(args.package)
        kbdata = get_keyboard_data(args.package)
        if not kbdata:
            logging.error("km-package-install: error: Could not download keyboard data for %s", args.package)
            sys.exit(3)
        kbdata_v = secure_lookup(kbdata, 'version')
        if installed_kmp_v and kbdata_v:
            kbdata_version = parse_version(kbdata_v)
            installed_kmp_ver = parse_version(installed_kmp_v)
            if kbdata_version == installed_kmp_ver:
                print("km-package-install: Version %s of the %s keyboard package is already installed."
                      % (installed_kmp_ver, args.package))
                sys.exit(1)
            elif kbdata_version > installed_kmp_ver:
                print("km-package-install: A newer version of %s keyboard package is available. Uninstalling old "
                      "version %s then downloading and installing new version %s."
                      % (args.package, installed_kmp_ver, kbdata_version))
                uninstall_kmp(args.package, args.shared)

        kmpfile = get_kmp(args.package)
        if kmpfile:
            try_install_kmp(kmpfile, "keyboard package " + args.package, args.bcp47, True, args.shared)
        else:
            logging.error("km-package-install: error: Could not download keyboard package %s", args.package)
            sys.exit(2)
    else:
        parser.print_usage()
        logging.error(
          "km-package-install: error: no arguments: either install a local kmp file " +
          "or specify a keyboard package id to download and install.")
        sys.exit(2)


if __name__ == "__main__":
    main()
