#!/usr/bin/env python3

import argparse

from compose_cms import Compose
from compose_cms.utils import ComposeObject


class NotNone:
    pass


class Usage:

    def __init__(self, name):
        self.usage = [name]

    def __call__(self, *args, **kwargs):
        self.usage.extend(args)
        return self

    def __str__(self):
        return ' '.join(self.usage)


def _package(usage, args, compose):
    parser = argparse.ArgumentParser(usage=str(usage('--package <package>')))
    parser.add_argument(
        '--package',
        help='Package ID',
        choices=compose.packages,
        required=True
    )
    parsed, remaining = parser.parse_known_args(args=args)
    # ---
    return compose.package(parsed.package), remaining


def _page(usage, args, compose):
    package, _ = _package(usage, args, compose)
    parser = argparse.ArgumentParser(usage=str(usage('--page <page>')))
    parser.add_argument(
        '--page',
        help='Page ID',
        choices=package.pages,
        required=True
    )
    parsed, remaining = parser.parse_known_args(args=args)
    # ---
    return package.page(parsed.page), remaining


def _configuration(usage, args, compose, action):
    parser = argparse.ArgumentParser(usage=str(usage))
    parser.add_argument(
        'configuration',
        type=str,
        nargs='+',
        help='Configuration in key1[=val1] [key2[=val2] ...] format.'
    )
    parsed, _ = parser.parse_known_args(args=args)
    config = {}
    # check syntax
    for kv in parsed.configuration:
        k, v, *rest = (kv.split('=') + [None]) if action == 'set' else [kv, None]
        if action == 'set' and (v is None or len(rest) > 1):
            raise ValueError('Configuration must be passed using the syntax key=val.')
        config[k] = v
    # ---
    return config, []


def _theme_db(compose):
    package = compose.package('core')
    configuration = package.configuration()
    theme_pkg, theme_name = configuration.get('theme').split(':')
    db = compose.database('core', 'theme_configuration')
    key = '{}__{}'.format(theme_pkg, theme_name)
    return db, key


def package_enable(usage, args, compose):
    package, _ = _package(usage, args, compose)
    package.enable()


def package_disable(usage, args, compose):
    package, _ = _package(usage, args, compose)
    package.disable()


def page_enable(usage, args, compose):
    page, _ = _page(usage, args, compose)
    page.enable()


def page_disable(usage, args, compose):
    page, _ = _page(usage, args, compose)
    page.disable()


def configuration_get(usage, args, compose):
    package, args = _package(usage, args, compose)
    keys, _ = _configuration(usage, args, compose, 'get')
    configuration = package.configuration()
    for key in keys:
        value = configuration.get(key)
        print('{}={}'.format(key, str(value)))


def configuration_set(usage, args, compose):
    package, args = _package(usage, args, compose)
    cfg, _ = _configuration(usage, args, compose, 'set')
    configuration = package.configuration()
    for key, value in cfg.items():
        if value == NotNone:
            continue
        configuration.set(key, value)


def theme_get(usage, args, compose):
    keys, _ = _configuration(usage, args, compose, 'get')
    db, cfg_key = _theme_db(compose)
    entry = db.read(cfg_key)
    for key in keys:
        value = entry[key]
        print('{}={}'.format(key, str(value)))


def theme_set(usage, args, compose):
    kv, _ = _configuration(usage, args, compose, 'set')
    db, cfg_key = _theme_db(compose)
    entry = db.read(cfg_key) if db.key_exists(cfg_key) else ComposeObject()
    for key, value in kv.items():
        entry[key] = value
    db.write(cfg_key, entry)


SUPPORTED_ACTIONS = {
    'package/enable': package_enable,
    'package/disable': package_disable,
    'page/enable': page_enable,
    'page/disable': page_disable,
    'configuration/get': configuration_get,
    'configuration/set': configuration_set,
    'theme/get': theme_get,
    'theme/set': theme_set,
}


if __name__ == '__main__':
    _usage = Usage('compose')
    _parser = argparse.ArgumentParser(usage=str(_usage))
    # ---
    _parser.add_argument('--workspace', '-C',
                         default=None,
                         help='Directory where \\compose\\ is installed')
    _parser.add_argument('--userdata', '-U',
                         default=None,
                         help='Directory containing the user-data')
    _parser.add_argument('action',
                         nargs=1,
                         choices=SUPPORTED_ACTIONS.keys(),
                         help='Action to perform')
    _parsed, _remaining = _parser.parse_known_args()
    # execute action
    _action = _parsed.action[0]
    _compose = Compose(path=_parsed.workspace, userdata=_parsed.userdata)
    SUPPORTED_ACTIONS[_action](_usage, _remaining, _compose)
