"""``tmt about`` implementation"""

import re
from typing import Any

import tmt.log
import tmt.utils
import tmt.utils.hints
import tmt.utils.rest
from tmt.cli import Context, CustomGroup, pass_context
from tmt.cli._root import main
from tmt.options import option
from tmt.plugins import REGISTRIES, PluginRegistry
from tmt.utils import GeneralError
from tmt.utils.templates import render_template, render_template_file

TEMPLATES_RESOURCE = 'cli/templates/about'


@main.group(invoke_without_command=True, cls=CustomGroup)
@pass_context
def about(context: Context) -> None:
    """
    Show info about tmt itself, its plugins, documentation and other
    components.
    """

    if context.invoked_subcommand is None:
        context.obj.print(context.get_help())


def _render_plugins_list_rest(logger: tmt.log.Logger) -> str:
    registry_intro_map: dict[str, str] = {
        r'export\.([a-z]+)': 'Export plugins for {{ MATCH.group(1).lower() }}',
        r'test.check': 'Test check plugins',
        r'test.framework': 'Test framework plugins',
        r'package_managers': 'Package manager plugins',
        r'plan_shapers': 'Plan shapers',
        r'prepare.feature': 'prepare/feature plugins',
        r'prepare.install': 'prepare/install plugins',
        r'prepare.artifact.providers': 'prepare/artifact provider plugins',
        r'step\.([a-z]+)': '{{ MATCH.group(1).capitalize() }} step plugins',
    }

    def find_intro(registry: PluginRegistry[Any]) -> str:
        for pattern, intro_template in registry_intro_map.items():
            match = re.match(pattern, registry.name)

            if match is None:
                continue

            return render_template(intro_template, MATCH=match)

        raise GeneralError(f"Unknown plugin registry '{registry.name}'.")

    template_file = tmt.utils.resource_files(
        f"{TEMPLATES_RESOURCE}/plugins-ls.rst.j2",
        logger=logger,
        assert_file=True,
    )
    return render_template_file(
        template_file,
        REGISTRIES=REGISTRIES,
        find_intro=find_intro,
    )


def _ls(context: Context, how: str, content: Any) -> None:
    if how in ('pretty', 'rest'):
        context.obj.print(
            tmt.utils.rest.render_rst(content, context.obj.logger) if how == 'pretty' else content
        )

    elif how in ('json', 'yaml'):
        context.obj.print(
            tmt.utils.to_json(content) if how == 'json' else tmt.utils.to_yaml(content)
        )


@about.group(invoke_without_command=True, cls=CustomGroup)
@pass_context
def plugins(context: Context) -> None:
    """
    Show info about tmt plugins.
    """

    if context.invoked_subcommand is None:
        context.obj.print(context.get_help())


@plugins.command(name='ls')
@option(
    '-h',
    '--how',
    choices=['json', 'yaml', 'rest', 'pretty'],
    default='pretty',
    help='Output format.',
)
@pass_context
def plugins_ls(context: Context, how: str) -> None:
    """
    List discovered tmt plugins.
    """

    if how in ('pretty', 'rest'):
        _ls(context, how, _render_plugins_list_rest(context.obj.logger))

    elif how in ('json', 'yaml'):
        _ls(
            context,
            how,
            {registry.name: list(registry.iter_plugin_ids()) for registry in REGISTRIES},
        )


@about.group(invoke_without_command=True, cls=CustomGroup)
@option('--hint', 'hint_ids', metavar='ID', multiple=True, help='Hint to display.')
@pass_context
def hints(context: Context, hint_ids: Any) -> None:
    """
    Show hints on various topics.
    """

    if hint_ids:
        for hint in tmt.utils.hints.get_hints(*hint_ids):
            context.obj.print(hint.render(context.obj.logger))

    elif context.invoked_subcommand is None:
        context.obj.print(context.get_help())


@hints.command(name='ls')
@option(
    '-h',
    '--how',
    choices=['json', 'yaml', 'rest', 'pretty'],
    default='pretty',
    help='Output format.',
)
@pass_context
def hints_ls(context: Context, how: str) -> None:
    """
    List discovered tmt hints.
    """

    template_file = tmt.utils.resource_files(
        f"{TEMPLATES_RESOURCE}/hints-ls.rst.j2",
        logger=context.obj.logger,
        assert_file=True,
    )
    if how in ('pretty', 'rest'):
        _ls(
            context,
            how,
            render_template_file(
                template_file,
                HINTS=tmt.utils.hints.HINTS,
            ),
        )

    elif how in ('json', 'yaml'):
        _ls(context, how, {hint_id: hint.text for hint_id, hint in tmt.utils.hints.HINTS.items()})
