"""Brief API routes.

POST /api/v1/brief/run
    Body: {"trigger": "schedule"|"manual", "show_id": optional, "run_date": optional}
    Auth: Bearer token from `BRIEF_SERVICE_API_KEYS`.
    Returns: {"status":"processing", ...} synchronously, work runs in background.

GET /api/v1/brief/runs/{brief_run_id}
    Returns the city_briefs_runs row + linked city_briefs row + stage snapshot.

GET /api/v1/briefs
    Recent briefs (one row per show) for inspection.
"""

from __future__ import annotations

import asyncio
import logging
from datetime import date
from typing import Any
from uuid import UUID

from fastapi import APIRouter, Header, HTTPException, Query
from pydantic import BaseModel, Field

from app.config import settings
from app.pipeline.orchestrator import OrchestrateBriefsService
from app.pipeline.stages import today_in_app_tz
from app.repositories import brief_repo, run_repo

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1/brief", tags=["brief"])


class BriefRunRequest(BaseModel):
    trigger: str = Field(default="manual", description="schedule | manual")
    show_id: str | None = None  # one-show scope (manual debugging)
    run_date: date | None = None  # default: today in APP_TIMEZONE


class BriefRunResponse(BaseModel):
    status: str
    briefs: list[dict[str, Any]] = Field(default_factory=list)
    brief_run_ids: list[str] = Field(default_factory=list)
    started_at: str
    error: str | None = None


# Singleton — instantiated lazily per-run to allow clean provider lifecycle.
_active_service: OrchestrateBriefsService | None = None


def _authenticate(authorization: str | None, x_api_key: str | None) -> None:
    """Accept either `Authorization: Bearer <token>` or `X-API-Key: <token>`."""
    candidate: str | None = None
    if authorization:
        parts = authorization.split(" ", 1)
        if len(parts) == 2 and parts[0].lower() == "bearer" and parts[1].strip():
            candidate = parts[1].strip()
    if not candidate and x_api_key:
        candidate = x_api_key.strip()
    if not candidate or candidate not in settings.accepted_api_keys:
        raise HTTPException(status_code=401, detail="invalid or missing API key")


@router.post("/run", response_model=BriefRunResponse, status_code=202)
async def run_pipeline(
    body: BriefRunRequest,
    authorization: str | None = Header(default=None),
    x_api_key: str | None = Header(default=None, alias="X-API-Key"),
) -> BriefRunResponse:
    _authenticate(authorization, x_api_key)
    accepted = settings.accepted_api_keys
    if not accepted:
        logger.error("no BRIEF_SERVICE_API_KEYS configured; refusing run")
        raise HTTPException(status_code=503, detail="service not configured")

    run_date = body.run_date or today_in_app_tz()

    service = OrchestrateBriefsService()
    # Background it so the HTTP call returns to n8n fast (n8n Schedule Trigger
    # is not a webhook — the worker just fires-and-logs; still, async is
    # friendlier to the bridge).
    try:
        summary = await service.run(trigger=body.trigger, run_date=run_date)
    finally:
        await service.aclose()

    briefs = summary.get("briefs", [])
    brief_run_ids = [str(b.get("brief_run_id")) for b in briefs if b.get("brief_run_id")]
    return BriefRunResponse(
        status=summary.get("status", "ok"),
        briefs=briefs,
        brief_run_ids=brief_run_ids,
        started_at=summary.get("started_at", ""),
        error=summary.get("error"),
    )


@router.get("/runs/{brief_run_id}")
async def fetch_run(
    brief_run_id: UUID,
    authorization: str | None = Header(default=None),
    x_api_key: str | None = Header(default=None, alias="X-API-Key"),
) -> dict[str, Any]:
    _authenticate(authorization, x_api_key)
    run_row = await run_repo.fetch(brief_run_id)
    if not run_row:
        raise HTTPException(status_code=404, detail="brief_run_id not found")
    brief = None
    if run_row.get("show_id"):
        brief = await brief_repo.fetch_by_show(run_row["show_id"])
    return {
        "brief_run_id": run_row["brief_run_id"],
        "show_id": run_row.get("show_id"),
        "show_date": run_row.get("show_date"),
        "status": run_row.get("status"),
        "stages": {k: run_row.get(k) for k in (
            "hub_lookup", "previous_show_lookup", "historical_sales_lookup",
            "voice_profile_load", "youtube_transcripts",
            "perplexity_city", "perplexity_news",
            "openai_fact_check", "openai_generation", "claude_ranking",
            "html_generation", "vps_deployment", "url_verification",
            "og_verification",
        )},
        "started_at": run_row.get("started_at"),
        "completed_at": run_row.get("completed_at"),
        "duration": run_row.get("duration"),
        "error": run_row.get("error"),
        "retry_count": run_row.get("retry_count"),
        "brief": brief,
    }


@router.get("/briefs")
async def recent_briefs(
    limit: int = Query(default=20, ge=1, le=100),
    authorization: str | None = Header(default=None),
    x_api_key: str | None = Header(default=None, alias="X-API-Key"),
) -> dict[str, Any]:
    _authenticate(authorization, x_api_key)
    briefs = await brief_repo.recent_briefs(limit=limit)
    return {"count": len(briefs), "briefs": briefs}