"""
Jinja2 template rendering system for Art-DAG servers.

Provides a unified template environment that can load from:
1. The shared artdag_common/templates directory
2. App-specific template directories

Usage:
    from artdag_common import create_jinja_env, render

    # In app initialization
    templates = create_jinja_env("app/templates")

    # In route handler
    return render(templates, "runs/detail.html", request, run=run, user=user)
"""

from pathlib import Path
from typing import Any, Optional, Union

from fastapi import Request
from fastapi.responses import HTMLResponse
from jinja2 import Environment, ChoiceLoader, FileSystemLoader, PackageLoader, select_autoescape

from .constants import (
    TAILWIND_CDN,
    HTMX_CDN,
    CYTOSCAPE_CDN,
    DAGRE_CDN,
    CYTOSCAPE_DAGRE_CDN,
    TAILWIND_CONFIG,
    NODE_COLORS,
    STATUS_COLORS,
)


def create_jinja_env(*template_dirs: Union[str, Path]) -> Environment:
    """
    Create a Jinja2 environment with the shared templates and optional app-specific dirs.

    Args:
        *template_dirs: Additional template directories to search (app-specific)

    Returns:
        Configured Jinja2 Environment

    Example:
        env = create_jinja_env("/app/templates", "/app/custom")
    """
    loaders = []

    # Add app-specific directories first (higher priority)
    for template_dir in template_dirs:
        path = Path(template_dir)
        if path.exists():
            loaders.append(FileSystemLoader(str(path)))

    # Add shared templates from this package (lower priority, fallback)
    loaders.append(PackageLoader("artdag_common", "templates"))

    env = Environment(
        loader=ChoiceLoader(loaders),
        autoescape=select_autoescape(["html", "xml"]),
        trim_blocks=True,
        lstrip_blocks=True,
    )

    # Add global context available to all templates
    env.globals.update({
        "TAILWIND_CDN": TAILWIND_CDN,
        "HTMX_CDN": HTMX_CDN,
        "CYTOSCAPE_CDN": CYTOSCAPE_CDN,
        "DAGRE_CDN": DAGRE_CDN,
        "CYTOSCAPE_DAGRE_CDN": CYTOSCAPE_DAGRE_CDN,
        "TAILWIND_CONFIG": TAILWIND_CONFIG,
        "NODE_COLORS": NODE_COLORS,
        "STATUS_COLORS": STATUS_COLORS,
    })

    # Add custom filters
    env.filters["truncate_hash"] = truncate_hash
    env.filters["format_size"] = format_size
    env.filters["status_color"] = status_color

    return env


def render(
    env: Environment,
    template_name: str,
    request: Request,
    status_code: int = 200,
    **context: Any,
) -> HTMLResponse:
    """
    Render a template to an HTMLResponse.

    Args:
        env: Jinja2 environment
        template_name: Template file path (e.g., "runs/detail.html")
        request: FastAPI request object
        status_code: HTTP status code (default 200)
        **context: Template context variables

    Returns:
        HTMLResponse with rendered content
    """
    template = env.get_template(template_name)
    html = template.render(request=request, **context)
    return HTMLResponse(html, status_code=status_code)


def render_fragment(
    env: Environment,
    template_name: str,
    **context: Any,
) -> str:
    """
    Render a template fragment to a string (for HTMX partial updates).

    Args:
        env: Jinja2 environment
        template_name: Template file path
        **context: Template context variables

    Returns:
        Rendered HTML string
    """
    template = env.get_template(template_name)
    return template.render(**context)


# Custom Jinja2 filters

def truncate_hash(value: str, length: int = 16) -> str:
    """Truncate a hash to specified length with ellipsis."""
    if not value:
        return ""
    if len(value) <= length:
        return value
    return f"{value[:length]}..."


def format_size(size_bytes: Optional[int]) -> str:
    """Format file size in human-readable form."""
    if size_bytes is None:
        return "Unknown"
    if size_bytes < 1024:
        return f"{size_bytes} B"
    elif size_bytes < 1024 * 1024:
        return f"{size_bytes / 1024:.1f} KB"
    elif size_bytes < 1024 * 1024 * 1024:
        return f"{size_bytes / (1024 * 1024):.1f} MB"
    else:
        return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"


def status_color(status: str) -> str:
    """Get Tailwind CSS class for a status."""
    return STATUS_COLORS.get(status, STATUS_COLORS["pending"])
