"""
FastAPI template API router — agent template gallery and deploy endpoints.

Templates are global (not tenant-scoped): any authenticated portal user can
browse them. Only tenant admins can deploy a template (creates an Agent snapshot).

Mounted at /api/portal in gateway/main.py alongside other portal routers.

Endpoints:
  GET  /api/portal/templates              — list active templates (all authenticated users)
  GET  /api/portal/templates/{id}         — get template detail (all authenticated users)
  POST /api/portal/templates/{id}/deploy  — deploy template as agent (tenant admin only)

Locale-aware responses:
  Pass ?locale=es or ?locale=pt to receive translated name/description/persona fields.
  English is the base — translations overlay, never replace stored English values in DB.
  Unsupported locales silently fall back to English.
"""

from __future__ import annotations

import uuid
from datetime import datetime
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Query, status
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from shared.api.portal import AgentResponse
from shared.api.rbac import PortalCaller, get_portal_caller, require_tenant_admin
from shared.db import get_session
from shared.models.tenant import Agent, AgentTemplate
from shared.rls import current_tenant_id

templates_router = APIRouter(prefix="/api/portal", tags=["templates"])


# ---------------------------------------------------------------------------
# Pydantic schemas
# ---------------------------------------------------------------------------


class TemplateResponse(BaseModel):
    id: str
    name: str
    role: str
    description: str
    category: str
    persona: str
    system_prompt: str
    model_preference: str
    tool_assignments: list[Any]
    escalation_rules: list[Any]
    is_active: bool
    sort_order: int
    created_at: datetime

    model_config = {"from_attributes": True}

    @classmethod
    def from_orm(cls, tmpl: AgentTemplate, locale: str = "en") -> "TemplateResponse":
        """
        Build a TemplateResponse from an ORM AgentTemplate.

        When locale != 'en' and the template's translations map contains the
        locale key, translated name/description/persona fields are overlaid over
        the English defaults. English base fields are never overwritten in the DB.
        """
        name = tmpl.name
        description = tmpl.description
        persona = tmpl.persona

        if locale != "en":
            translations: dict[str, Any] = tmpl.translations or {}
            locale_data: dict[str, Any] = translations.get(locale, {})
            if locale_data:
                name = locale_data.get("name", name)
                description = locale_data.get("description", description)
                persona = locale_data.get("persona", persona)

        return cls(
            id=str(tmpl.id),
            name=name,
            role=tmpl.role,
            description=description,
            category=tmpl.category,
            persona=persona,
            system_prompt=tmpl.system_prompt,
            model_preference=tmpl.model_preference,
            tool_assignments=tmpl.tool_assignments,
            escalation_rules=tmpl.escalation_rules,
            is_active=tmpl.is_active,
            sort_order=tmpl.sort_order,
            created_at=tmpl.created_at,
        )


class TemplateDeployRequest(BaseModel):
    tenant_id: uuid.UUID


class TemplateDeployResponse(BaseModel):
    agent: AgentResponse


# ---------------------------------------------------------------------------
# Endpoints
# ---------------------------------------------------------------------------


@templates_router.get("/templates", response_model=list[TemplateResponse])
async def list_templates(
    locale: str = Query(default="en", description="Response locale: en | es | pt"),
    caller: PortalCaller = Depends(get_portal_caller),
    session: AsyncSession = Depends(get_session),
) -> list[TemplateResponse]:
    """
    List all active agent templates.

    Available to all authenticated portal users (any role).
    Templates are global — not tenant-scoped, no RLS needed.
    Returns templates ordered by sort_order ascending, then name.

    Pass ?locale=es or ?locale=pt to receive translated name/description/persona fields.
    Unsupported locales fall back to English.
    """
    result = await session.execute(
        select(AgentTemplate)
        .where(AgentTemplate.is_active == True)  # noqa: E712
        .order_by(AgentTemplate.sort_order.asc(), AgentTemplate.name.asc())
    )
    templates = result.scalars().all()
    return [TemplateResponse.from_orm(t, locale=locale) for t in templates]


@templates_router.get("/templates/{template_id}", response_model=TemplateResponse)
async def get_template(
    template_id: uuid.UUID,
    locale: str = Query(default="en", description="Response locale: en | es | pt"),
    caller: PortalCaller = Depends(get_portal_caller),
    session: AsyncSession = Depends(get_session),
) -> TemplateResponse:
    """
    Get a single active agent template by ID.

    Returns 404 if the template does not exist or is inactive.
    Available to all authenticated portal users (any role).

    Pass ?locale=es or ?locale=pt to receive translated fields.
    """
    result = await session.execute(
        select(AgentTemplate).where(
            AgentTemplate.id == template_id,
            AgentTemplate.is_active == True,  # noqa: E712
        )
    )
    tmpl = result.scalar_one_or_none()
    if tmpl is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Template not found")
    return TemplateResponse.from_orm(tmpl, locale=locale)


@templates_router.post(
    "/templates/{template_id}/deploy",
    response_model=TemplateDeployResponse,
    status_code=status.HTTP_201_CREATED,
)
async def deploy_template(
    template_id: uuid.UUID,
    body: TemplateDeployRequest,
    caller: PortalCaller = Depends(get_portal_caller),
    session: AsyncSession = Depends(get_session),
) -> TemplateDeployResponse:
    """
    Deploy a template as an independent Agent snapshot for a tenant.

    Guard: tenant admin only (customer_operator gets 403).
    The deployed Agent is a point-in-time snapshot — subsequent changes to the
    template do not affect already-deployed agents.

    Returns 404 if template not found. Returns 403 if caller lacks admin access
    to the specified tenant.
    """
    # RBAC: tenant admin check (reuses require_tenant_admin from rbac.py)
    await require_tenant_admin(body.tenant_id, caller, session)

    # Fetch template (404 if not found or inactive)
    result = await session.execute(
        select(AgentTemplate).where(AgentTemplate.id == template_id)
    )
    tmpl = result.scalar_one_or_none()
    if tmpl is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Template not found")

    # Create Agent snapshot scoped to the target tenant
    token = current_tenant_id.set(body.tenant_id)
    try:
        agent = Agent(
            tenant_id=body.tenant_id,
            name=tmpl.name,
            role=tmpl.role,
            persona=tmpl.persona,
            system_prompt=tmpl.system_prompt,
            model_preference=tmpl.model_preference,
            tool_assignments=tmpl.tool_assignments,
            escalation_rules=tmpl.escalation_rules,
            is_active=True,
        )
        session.add(agent)
        await session.commit()
        await session.refresh(agent)
    finally:
        current_tenant_id.reset(token)

    return TemplateDeployResponse(agent=AgentResponse.from_orm(agent))
