"""
Mizan SSR Template Backend — Django template engine that renders React via Bun.

    TEMPLATES = [
        {
            'BACKEND': 'mizan.ssr.MizanTemplates',
            'DIRS': [BASE_DIR / 'frontend'],
            'OPTIONS': {
                'worker': 'path/to/mizan-ssr/src/worker.tsx',
            },
        },
    ]

Then: render(request, 'components/Hello.tsx', {'name': 'World'})
"""

from __future__ import annotations

import os
from typing import Any

from django.template import TemplateDoesNotExist
from django.template.backends.base import BaseEngine
from django.utils.safestring import mark_safe

from .bridge import SSRBridge


class MizanTemplate:
    """Renders a .tsx/.jsx file via the SSR bridge."""

    def __init__(self, file_path: str, bridge: SSRBridge) -> None:
        self.file_path = file_path
        self.origin = None
        self._bridge = bridge

    def render(self, context: dict[str, Any] | None = None, request: Any = None) -> str:
        import json as _json

        props = dict(context) if context else {}
        props.pop("request", None)
        props.pop("csrf_token", None)

        result = self._bridge.render(self.file_path, props)

        # Serialize props as hydration data for client-side React
        hydration_json = _json.dumps(props, sort_keys=True, default=str)

        return mark_safe(
            f'<div id="mizan-root">{result.html}</div>'
            f'<script>window.__MIZAN_SSR_DATA__={hydration_json}</script>'
        )


class MizanTemplates(BaseEngine):
    """
    Django template backend that renders React components via Bun.

    Template names are file paths resolved against DIRS.
    Same model as Django's built-in template engines.
    """

    def __init__(self, params: dict[str, Any]) -> None:
        options = params.pop("OPTIONS", {})
        params.setdefault("NAME", "mizan")
        params.setdefault("APP_DIRS", False)
        super().__init__(params)

        self._worker = options.get("worker")
        self._timeout = options.get("timeout", 5)
        self._bridge: SSRBridge | None = None

        if not self._worker:
            raise ValueError(
                "MizanTemplates requires OPTIONS['worker'] — "
                "the path to mizan-ssr's worker.tsx"
            )

    def get_bridge(self) -> SSRBridge:
        if self._bridge is None:
            self._bridge = SSRBridge(
                worker_path=self._worker,
                timeout=self._timeout,
            )
        return self._bridge

    def get_template(self, template_name: str) -> MizanTemplate:
        for dir_path in self.dirs:
            file_path = os.path.join(dir_path, template_name)
            if os.path.isfile(file_path):
                return MizanTemplate(
                    os.path.abspath(file_path),
                    self.get_bridge(),
                )
        raise TemplateDoesNotExist(template_name)

    def from_string(self, template_code: str) -> MizanTemplate:
        raise TemplateDoesNotExist(
            "MizanTemplates renders .tsx files, not template strings."
        )
