#!/usr/bin/env python3
import os
import platform
import sys
import tempfile

from pathlib import Path
from textwrap import dedent

import click

from .layout import KeyboardLayout
from .xkb_manager import XKBManager, XKB_ROOT, XKB_HOME


def xkb_ensure_xkb_config_is_ready():
    """ Ensure there is an XKB configuration in user-space. """
    # See xkblayout.py for a more extensive version of this feature:
    # https://gitlab.freedesktop.org/whot/xkblayout

    # ensure all expected directories exist (don't care about 'geometry')
    XKB_HOME.mkdir(exist_ok=True)
    for subdir in ['compat', 'keycodes', 'rules', 'symbols', 'types']:
        (XKB_HOME / subdir).mkdir(exist_ok=True)

    # ensure there are XKB rules
    # (new locales and symbols will be added by XKBManager)
    for ruleset in ['evdev']:  # add 'base', too?
        # xkb/rules/evdev
        rules = XKB_HOME / 'rules' / ruleset
        if not rules.exists():
            with open(rules, 'w') as rulesfile:
                rulesfile.write(dedent(f'''
                    // Generated by Kalamine
                    // Include the system '{ruleset}' file
                    ! include %S/{ruleset}
                    '''))
        # xkb/rules/evdev.xml
        xmlpath = XKB_HOME / 'rules' / f'{ruleset}.xml'
        if not xmlpath.exists():
            with open(xmlpath, 'w') as xmlfile:
                xmlfile.write(dedent(f'''\
                    <?xml version="1.0" encoding="UTF-8"?>
                    <!DOCTYPE xkbConfigRegistry SYSTEM "xkb.dtd">
                    <!-- Generated by Kalamine -->
                    <xkbConfigRegistry version="1.1">
                        <layoutList/>
                    </xkbConfigRegistry>
                    '''))


@click.group()
def cli():
    if platform.system() != 'Linux':
        sys.exit('This command is only compatible with GNU/Linux, sorry.')


@cli.command()
@click.argument('input', nargs=1, type=click.Path(exists=True))
def apply(input):
    """ Apply a Kalamine layout. """

    layout = KeyboardLayout(input)
    with tempfile.NamedTemporaryFile(mode='w+', suffix='.xkb', encoding='utf-8') as temp_file:
        try:
            temp_file.write(layout.xkb)
            os.system(f"xkbcomp -w0 {temp_file.name} $DISPLAY")
        finally:
            temp_file.close()


@cli.command()
@click.argument('layouts', nargs=-1, type=click.Path(exists=True))
def install(layouts):
    """ Install a list of Kalamine layouts. """

    if not layouts:
        return

    kb_locales = set()
    kb_layouts = []
    for file in layouts:
        layout = KeyboardLayout(file)
        kb_layouts.append(layout)
        kb_locales.add(layout.meta['locale'])

    xkb_root = XKBManager(XKB_ROOT)

    def xkb_install(xkb):
        for layout in kb_layouts:
            xkb.add(layout)
        xkb.clean()
        xkb.update()
        print()
        print('Successfully installed.')

    # EAFP (Easier to Ask Forgiveness than Permission)
    try:
        xkb_install(xkb_root)
        print(f"You can try the layout{'s' if len(layouts) > 1 else ''} with:")
        for locale, variants in xkb_root.index:
            for name in variants.keys():
                print(f"    setxkbmap {locale} -variant {name}")
        print()

    except PermissionError:
        print('    Not writable: switching to user-space.')
        print()
        xkb_ensure_xkb_config_is_ready()
        xkb_home = XKBManager(XKB_HOME)
        xkb_install(xkb_home)
        print('Warning: user-space layouts only work with Wayland.')
        print()


@cli.command()
@click.argument('mask')  # [locale]/[name]
def remove(mask):
    """ Remove a list of Kalamine layouts. """

    def xkb_remove(root):
        xkb = XKBManager(root)
        xkb.clean()
        for locale, variants in xkb.list(mask).items():
            for name in variants.keys():
                xkb.remove(locale, name)
        xkb.update()

    # EAFP (Easier to Ask Forgiveness than Permission)
    try:
        xkb_remove(XKB_ROOT)
    except PermissionError:
        xkb_remove(XKB_HOME)


@cli.command()
@click.argument('mask', default='*')
@click.option('--all', '-a', is_flag=True)
def list(mask, all):
    """ List installed Kalamine layouts. """

    for root in [XKB_ROOT, XKB_HOME]:
        filtered = {}

        xkb = XKBManager(root)
        layouts = xkb.list_all(mask) if all else xkb.list(mask)
        for locale, variants in sorted(layouts.items()):
            for name, desc in sorted(variants.items()):
                filtered[f"{locale}/{name}"] = desc

        if mask == "*" and root == XKB_ROOT and xkb.has_custom_symbols():
            filtered['custom'] = ''

        if bool(filtered):
            print(root)
            for id, desc in filtered.items():
                print(f"    {id:<24} {desc}")
