"""Jinja2 environment and extensions loading."""

from __future__ import annotations

from typing import Any

from jinja2 import Environment, StrictUndefined

from aiclimate.exceptions import UnknownExtension


class ExtensionLoaderMixin:
    """Mixin providing sane loading of extensions specified in a given context.

    The context is being extracted from the keyword arguments before calling
    the next parent class in line of the child.
    """

    def __init__(self, *, context: dict[str, Any] | None = None, **kwargs: Any) -> None:
        """Initialize the Jinja2 Environment object while loading extensions.

        Does the following:

        1. Establishes default_extensions (currently just a Time feature)
        2. Reads extensions set in the template config _extensions key.
        3. Attempts to load the extensions. Provides useful error if fails.
        """
        context = context or {}

        default_extensions = [
            'aiclimate.extensions.JsonifyExtension',
            'aiclimate.extensions.RandomStringExtension',
            'aiclimate.extensions.SlugifyExtension',
            'aiclimate.extensions.TimeExtension',
            'aiclimate.extensions.UUIDExtension',
        ]
        extensions = default_extensions + self._read_extensions(context)

        try:
            super().__init__(extensions=extensions, **kwargs)  # type: ignore[call-arg]
        except ImportError as err:
            msg = f'Unable to load extension: {err}'
            raise UnknownExtension(msg) from err

    def _read_extensions(self, context: dict[str, Any]) -> list[str]:
        """Return list of extensions as str to be passed on to the Jinja2 env.

        If context does not contain the relevant info, return an empty
        list instead.
        """
        for key in ('aiclimate', 'cookiecutter'):
            if key in context and '_extensions' in context[key]:
                return [str(ext) for ext in context[key]['_extensions']]
        return []


class StrictEnvironment(ExtensionLoaderMixin, Environment):
    """Create strict Jinja2 environment.

    Jinja2 environment will raise error on undefined variable in template-
    rendering context.
    """

    def __init__(self, **kwargs: Any) -> None:
        """Set the standard aiclimate StrictEnvironment.

        Also loading extensions defined in the template config's _extensions key.
        """
        super().__init__(undefined=StrictUndefined, **kwargs)
