"""
Server-generert PDF for utskriftsklare turneringsdokumenter (scorekort,
startliste, cart-tags, resultatliste). Se ARCHITECTURE_DECISIONS.md ADR-097.

Rendrer den EKTE Next.js-utskriftssiden i en headless Chromium (Playwright)
i stedet for å duplisere layouten i en egen server-side malmotor -- én kilde
til sannhet for visuell layout (samme React-komponent brukeren allerede ser
i forhåndsvisningen). Siden selv setter @page-CSS-regelen ut fra valgt
papirstørrelse/retning (styrt av URL-parametrene denne ruten konstruerer);
Playwright sin prefer_css_page_size=True bruker den regelen direkte -- ingen
egen mm-utregning her, dupliseres ikke.

Sesjonscookien fra DENNE forespørselen videreføres til Playwright sin
nettleserkontekst før navigering, slik at siden gjør sine egne fetch()-kall
til API-et akkurat som om en ekte innlogget nettleser lastet den -- ingen
egen auth-vei for renderingen.

`path` konstrueres ALDRI fra klient-input direkte (SSRF-hensyn) -- kun
`kind` + verifiserte IDer, malen for hver `kind` er hardkodet her.
"""

from typing import Literal

from fastapi import APIRouter, Depends, Request, Response
from playwright.async_api import async_playwright
from pydantic import BaseModel

from ..auth import SESSION_COOKIE_NAME, get_authorized_org
from ..db import org_connection
from ..errors import app_error

router = APIRouter()

# Samme Docker-nettverk som teecup_api (docker-compose.yml) -- internt
# tjenestenavn, aldri en offentlig URL.
_FRONTEND_ORIGIN = "http://teecup_frontend:3000"
_FRONTEND_HOST = "teecup_frontend"

PrintKind = Literal["scorecard", "startlist", "cart-tags", "resultlist"]
Paper = Literal["A4", "Letter", "A5", "A3", "A2"]
Orientation = Literal["portrait", "landscape"]

# resultlist er turneringsomfattende (leaderboard-endepunktene), trenger
# verken runde eller økt. De tre andre trenger ETT av (runde ELLER økt) --
# hvilket avhenger av om turneringen er individuell eller Cup-format, ikke
# noe denne ruten selv vet -- frontend sender riktig ID.
_SCOPED_KINDS: set[PrintKind] = {"scorecard", "startlist", "cart-tags"}


class PrintPdfRequest(BaseModel):
    kind: PrintKind
    tournament_id: str
    round_id: str | None = None
    session_id: str | None = None
    paper: Paper = "A4"
    orientation: Orientation = "portrait"


async def _verify_scope(conn, tournament_id: str, round_id: str | None, session_id: str | None) -> None:
    # org_connection har allerede satt app.current_org -- RLS gjør at disse
    # EXISTS-sjekkene stille returnerer usann for en rad i en ANNEN
    # organisasjon, selv om raden faktisk finnes. Samme mønster som resten
    # av API-et stoler på (ADR-001/003), ikke en egen sjekk her.
    tournament_exists = await conn.fetchval(
        "SELECT EXISTS (SELECT 1 FROM tournament WHERE id = $1)", tournament_id
    )
    if not tournament_exists:
        raise app_error(404, "NOT_FOUND", "Fant ingen turnering med denne IDen i organisasjonen.")
    if round_id is not None:
        exists = await conn.fetchval(
            "SELECT EXISTS (SELECT 1 FROM tournament_round WHERE id = $1 AND tournament_id = $2)",
            round_id,
            tournament_id,
        )
        if not exists:
            raise app_error(404, "NOT_FOUND", "Fant ingen runde med denne IDen i turneringen.")
    if session_id is not None:
        exists = await conn.fetchval(
            'SELECT EXISTS (SELECT 1 FROM session WHERE id = $1 AND tournament_id = $2)',
            session_id,
            tournament_id,
        )
        if not exists:
            raise app_error(404, "NOT_FOUND", "Fant ingen økt med denne IDen i turneringen.")


def _build_path(organization_id: str, body: PrintPdfRequest) -> str:
    params = [f"org={organization_id}", f"paper={body.paper}", f"orientation={body.orientation}"]
    if body.round_id:
        params.append(f"roundId={body.round_id}")
    if body.session_id:
        params.append(f"sessionId={body.session_id}")
    return f"/tournaments/{body.tournament_id}/print/{body.kind}?{'&'.join(params)}"


@router.post("/orgs/{organization_id}/print/pdf")
async def render_print_pdf(
    body: PrintPdfRequest,
    request: Request,
    organization_id: str = Depends(get_authorized_org),
) -> Response:
    token = request.cookies.get(SESSION_COOKIE_NAME)
    if not token:
        raise app_error(401, "NOT_AUTHENTICATED", "Ikke innlogget.")

    if body.kind in _SCOPED_KINDS and not body.round_id and not body.session_id:
        raise app_error(400, "MISSING_SCOPE", "Mangler runde- eller økt-ID for denne utskriftstypen.")

    async with org_connection(organization_id) as conn:
        await _verify_scope(conn, body.tournament_id, body.round_id, body.session_id)

    url = f"{_FRONTEND_ORIGIN}{_build_path(organization_id, body)}"

    async with async_playwright() as pw:
        browser = await pw.chromium.launch()
        try:
            context = await browser.new_context()
            await context.add_cookies(
                [
                    {
                        "name": SESSION_COOKIE_NAME,
                        "value": token,
                        "domain": _FRONTEND_HOST,
                        "path": "/",
                        "httpOnly": True,
                        "secure": False,
                    }
                ]
            )
            page = await context.new_page()
            await page.goto(url, wait_until="networkidle")
            try:
                # Hver utskriftsside setter dette attributtet på <body> først
                # NÅR all data er hentet OG lagt inn i DOM-en -- printer vi
                # før det, får vi enten "Laster..."-tilstanden eller mock-
                # dataene siden startet med, ikke ekte innhold.
                await page.wait_for_selector("[data-print-ready='true']", timeout=15000)
            except Exception:
                raise app_error(
                    504,
                    "PRINT_RENDER_TIMEOUT",
                    "Utskriftssiden ble ikke klar i tide. Prøv igjen.",
                )
            pdf_bytes = await page.pdf(print_background=True, prefer_css_page_size=True)
        finally:
            await browser.close()

    return Response(
        content=pdf_bytes,
        media_type="application/pdf",
        headers={"Content-Disposition": f'attachment; filename="teecup-{body.kind}.pdf"'},
    )
