"""Rendering Jinja templates and KDL nodes into HTML."""

import html
import re
from typing import TYPE_CHECKING, Any, Iterable

import jinja2
from kdl import parse as kdl_parse

from .errors import TemplateNotFoundException

if TYPE_CHECKING:
    from kdl import Node as KdlNode


def render_node_list(nodes: Iterable[KdlNode], escape_tag_bodies: bool = False) -> str:
    """Recursively turn KDL nodes into HTML tags."""
    html_result = []
    for node in nodes:
        if node.name == "-":
            # Passthrough
            html_result.append(
                " ".join(
                    [
                        html.escape(html.unescape(str(a)))
                        if escape_tag_bodies
                        else str(a)
                        for a in node.args
                    ]
                )
            )
            html_result.append(render_node_list(node.nodes, escape_tag_bodies))
            continue

        elif not re.match(r"[a-zA-Z][a-zA-Z0-9\-]*", node.name):
            continue

        tag = node.name
        props = " ".join(
            [
                (
                    html.escape(html.unescape(k)) + '=' +
                        (html.escape(html.unescape(v))
                        if v not in (True, False)
                        else str(v).lower())
                    if v not in ("", None)
                    else html.escape(html.unescape(k))
                )
                for k, v in node.props.items()
                if k != ""
            ]
        )
        args = " ".join(
            [
                html.escape(html.unescape(str(a))) if escape_tag_bodies else str(a)
                for a in node.args
            ]
        )
        children = render_node_list(node.nodes, escape_tag_bodies)

        html_result.append(
            f"<{tag}{' ' if props else ''}{props}>{args}{children}</{tag}>"
        )

    return "".join(html_result)


def render_template(
    env: jinja2.Environment, template_name: str, opts: dict[str, Any] | None = None
) -> str:
    """Render a HTML template from a .kdl.j2 template name and an options dict."""
    if template_name.endswith(".html"):
        template_name = template_name[: -len(".html")] + ".kdl.j2"

    elif not template_name.endswith(".kdl.j2"):
        template_name += ".kdl.j2"

    try:
        template = env.get_template(template_name)

    except Exception as e:
        raise TemplateNotFoundException(template_name, e)

    rendered_kdl = template.render(**(opts or {}))

    doc = kdl_parse(rendered_kdl)
    return render_node_list(doc.nodes)
