from __future__ import annotations

import logging
from datetime import datetime, timezone
from typing import Any

from fastapi import Request
from fastapi.templating import Jinja2Templates

from services.navigation import NavigationService
from services.session import AuthSession
from services.unit_of_work import UnitOfWork


logger = logging.getLogger(__name__)


def format_datetime(value: Any) -> str:
    """Render datetime values consistently for templates."""
    if not isinstance(value, datetime):
        return ""
    if value.tzinfo is None:
        value = value.replace(tzinfo=timezone.utc)
    return value.strftime("%Y-%m-%d %H:%M UTC")


def currency_display(value: Any, currency_code: str | None) -> str:
    """Format numeric values with currency context."""
    if value is None:
        return "—"
    if isinstance(value, (int, float)):
        formatted_value = f"{value:,.2f}"
    else:
        formatted_value = str(value)
    if currency_code:
        return f"{currency_code} {formatted_value}"
    return formatted_value


def format_metric(value: Any, metric_name: str, currency_code: str | None = None) -> str:
    """Format metrics according to their semantic type."""
    if value is None:
        return "—"

    currency_metrics = {
        "npv",
        "inflows",
        "outflows",
        "net",
        "total_inflows",
        "total_outflows",
        "total_net",
    }
    if metric_name in currency_metrics and currency_code:
        return currency_display(value, currency_code)

    percentage_metrics = {"irr", "payback_period"}
    if metric_name in percentage_metrics:
        if isinstance(value, (int, float)):
            return f"{value:.2f}%"
        return f"{value}%"

    if isinstance(value, (int, float)):
        return f"{value:,.2f}"

    return str(value)


def percentage_display(value: Any) -> str:
    """Format numeric values as percentages."""
    if value is None:
        return "—"
    if isinstance(value, (int, float)):
        return f"{value:.2f}%"
    return f"{value}%"


def period_display(value: Any) -> str:
    """Format period values in years."""
    if value is None:
        return "—"
    if isinstance(value, (int, float)):
        if value == int(value):
            return f"{int(value)} years"
        return f"{value:.1f} years"
    return str(value)


def register_common_filters(templates: Jinja2Templates) -> None:
    templates.env.filters["format_datetime"] = format_datetime
    templates.env.filters["currency_display"] = currency_display
    templates.env.filters["format_metric"] = format_metric
    templates.env.filters["percentage_display"] = percentage_display
    templates.env.filters["period_display"] = period_display


def _sidebar_navigation_for_request(request: Request | None):
    if request is None:
        return None

    cached = getattr(request.state, "_navigation_sidebar_dto", None)
    if cached is not None:
        return cached

    session_context = getattr(request.state, "auth_session", None)
    if isinstance(session_context, AuthSession):
        session = session_context
    else:
        session = AuthSession.anonymous()

    try:
        with UnitOfWork() as uow:
            if not uow.navigation:
                logger.debug("Navigation repository unavailable for sidebar rendering")
                sidebar_dto = None
            else:
                service = NavigationService(uow.navigation)
                sidebar_dto = service.build_sidebar(session=session, request=request)
    except Exception:  # pragma: no cover - defensive fallback for templates
        logger.exception("Failed to build sidebar navigation during template render")
        sidebar_dto = None

    setattr(request.state, "_navigation_sidebar_dto", sidebar_dto)
    return sidebar_dto


def register_navigation_globals(templates: Jinja2Templates) -> None:
    templates.env.globals["get_sidebar_navigation"] = _sidebar_navigation_for_request


def create_templates() -> Jinja2Templates:
    templates = Jinja2Templates(directory="templates")
    register_common_filters(templates)
    register_navigation_globals(templates)
    return templates


__all__ = [
    "format_datetime",
    "currency_display",
    "format_metric",
    "percentage_display",
    "period_display",
    "register_common_filters",
    "register_navigation_globals",
    "create_templates",
]
