from nawah.config import Config
from nawah.classes import ATTR, EXTN

from typing import Dict, List

import logging, datetime, re, inspect

logger = logging.getLogger('nawah')


def _generate_ref():
    # [DOC] Initialise _api_ref Config Attr
    Config._api_ref = '# API Reference\n'
    # [DOC] Iterate over packages in ascending order
    for package in sorted(Config.modules_packages.keys()):
        # [DOC] Add package header
        Config._api_ref += f'- - -\n## Package: {package.replace("modules.", "")}\n'
        if not len(Config.modules_packages[package]):
            Config._api_ref += f'No modules\n'
        # [DOC] Iterate over package modules in ascending order
        for module in sorted(Config.modules_packages[package]):
            # [DOC] Add module header
            Config._api_ref += f'### Module: {module}\n'
            # [DOC] Add module description
            Config._api_ref += f'{Config.modules[module].__doc__}\n'
            # [DOC] Add module attrs header
            Config._api_ref += '#### Attrs\n'
            # [DOC] Iterate over module attrs to add attrs types, defaults (if any)
            for attr in Config.modules[module].attrs.keys():
                attr_ref = f'* {attr}:\n'
                if Config.modules[module].attrs[attr]._desc:
                    attr_ref += f'  * {Config.modules[module].attrs[attr]._desc}\n'
                attr_ref += f'  * Type: `{Config.modules[module].attrs[attr]}`\n'
                for default_attr in Config.modules[module].defaults.keys():
                    if (
                        default_attr == attr
                        or default_attr.startswith(f'{attr}.')
                        or default_attr.startswith(f'{attr}:')
                    ):
                        if type(Config.modules[module].defaults[default_attr]) == ATTR:
                            attr_ref += f'  * Default [{default_attr}]:\n'
                            attr_ref += f'	* Attr Type TYPE: `{Config.modules[module].defaults[default_attr]._args["type"]}`\n'
                        else:
                            attr_ref += f'  * Default [{default_attr}]: {Config.modules[module].defaults[default_attr]}\n'
                Config._api_ref += attr_ref
            if Config.modules[module].diff:
                Config._api_ref += f'#### Attrs Diff: {Config.modules[module].diff}\n'
            # [DOC] Add module methods
            Config._api_ref += '#### Methods\n'
            for method in Config.modules[module].methods.keys():
                Config._api_ref += f'##### Method: {method}\n'
                Config._api_ref += f'* Permissions Sets:\n'
                for permission in Config.modules[module].methods[method].permissions:
                    Config._api_ref += f'  * {permission.privilege}\n'
                    # [DOC] Add Query Modifier
                    if permission.query_mod:
                        Config._api_ref += f'	* Query Modifier:\n'
                        if type(permission.query_mod) == dict:
                            permission.query_mod = [permission.query_mod]
                        for i in range(len(permission.query_mod)):
                            Config._api_ref += f'	  * Set {i}:\n'
                            # [TODO] Improve nested list sets
                            if type(permission.query_mod[i]) != dict:
                                Config._api_ref += (
                                    f'		* List: {permission.query_mod[i]}\n'
                                )
                                continue
                            for attr in permission.query_mod[i].keys():
                                if type(permission.query_mod[i][attr]) == ATTR:
                                    Config._api_ref += f'		* {attr}:\n'
                                    Config._api_ref += f'		  * Attr Type TYPE: {permission.query_mod[i][attr]._args["type"]}\n'
                                else:
                                    Config._api_ref += (
                                        f'		* {attr}: {permission.query_mod[i][attr]}\n'
                                    )
                    else:
                        Config._api_ref += f'	* Query Modifier: None\n'
                    # [DOC] Add Doc Modifier
                    if permission.doc_mod:
                        Config._api_ref += f'	* Doc Modifier:\n'
                        if type(permission.doc_mod) == dict:
                            permission.doc_mod = [permission.doc_mod]
                        for i in range(len(permission.doc_mod)):
                            Config._api_ref += f'	  * Set {i}:\n'
                            for attr in permission.doc_mod[i].keys():
                                if type(permission.doc_mod[i][attr]) == ATTR:
                                    Config._api_ref += f'		* {attr}:\n'
                                    Config._api_ref += f'		  * Attr Type TYPE: `{permission.doc_mod[i][attr]._args["type"]}`\n'
                                else:
                                    Config._api_ref += (
                                        f'		* {attr}: {permission.doc_mod[i][attr]}\n'
                                    )
                    else:
                        Config._api_ref += f'	* Doc Modifier: None\n'
                # [DOC] Add Query Args
                if Config.modules[module].methods[method].query_args:
                    Config._api_ref += f'* Query Args Sets:\n'
                    for query_args_set in (
                        Config.modules[module].methods[method].query_args
                    ):
                        Config._api_ref += f'  * `{query_args_set}`\n'
                else:
                    Config._api_ref += f'* Query Args Sets: None\n'
                # [DOC] Add Doc Args
                if Config.modules[module].methods[method].doc_args:
                    Config._api_ref += f'* DOC Args Sets:\n'
                    for doc_args_set in Config.modules[module].methods[method].doc_args:
                        Config._api_ref += f'  * `{doc_args_set}`\n'
                else:
                    Config._api_ref += f'* Doc Args Sets: None\n'
            # [DOC] Add module extns
            if Config.modules[module].extns.keys():
                Config._api_ref += '#### Extended Attrs\n'
                for attr in Config.modules[module].extns.keys():
                    Config._api_ref += f'* {attr}:\n'
                    if type(Config.modules[module].extns[attr]) == EXTN:
                        Config._api_ref += f'  * Module: \'{Config.modules[module].extns[attr].module}\'\n'
                        Config._api_ref += f'  * Extend Attrs: \'{Config.modules[module].extns[attr].attrs}\'\n'
                        Config._api_ref += f'  * Force: \'{Config.modules[module].extns[attr].force}\'\n'
                    elif type(Config.modules[module].extns[attr]) == ATTR:
                        Config._api_ref += f'  * Attr Type TYPE: `{Config.modules[module].extns[attr]._args["type"]}`\n'
            else:
                Config._api_ref += '#### Extended Attrs: None\n'
            # [DOC] Add module cache sets
            if Config.modules[module].cache:
                Config._api_ref += '#### Cache Sets\n'
                for i in range(len(Config.modules[module].cache)):
                    Config._api_ref += f'* Set {i}:\n'
                    Config._api_ref += f'  * CACHE condition: `{_extract_lambda_body(Config.modules[module].cache[i].condition)}`\n'
                    Config._api_ref += (
                        f'  * CACHE period: {Config.modules[module].cache[i].period}\n'
                    )
            else:
                Config._api_ref += '#### Cache Sets: None\n'
            # [DOC] Add module analytics sets
            if Config.modules[module].analytics:
                Config._api_ref += '#### Analytics Sets\n'
                for i in range(len(Config.modules[module].analytics)):
                    Config._api_ref += f'* Set {i}:\n'
                    Config._api_ref += f'  * ANALYTIC condition: `{_extract_lambda_body(Config.modules[module].analytics[i].condition)}`\n'
                    Config._api_ref += f'  * ANALYTIC doc: `{_extract_lambda_body(Config.modules[module].analytics[i].doc)}`\n'
            else:
                Config._api_ref += '#### Analytics Sets: None\n'
    import os

    ref_file = os.path.join(
        Config._app_path,
        'refs',
        f'NAWAH_API_REF_{datetime.datetime.utcnow().strftime("%d-%b-%Y")}.md',
    )
    with open(ref_file, 'w') as f:
        f.write(Config._api_ref)
        logger.info(f'API reference generated and saved to: \'{ref_file}\'. Exiting.')
        exit(0)


def _extract_lambda_body(lambda_func):
    lambda_body = re.sub(
        r'^[a-z]+\s*=\s*lambda\s', '', inspect.getsource(lambda_func).strip()
    )
    if lambda_body.endswith(','):
        lambda_body = lambda_body[:-1]
    return lambda_body
