"""Endpoints del timbrado de CFDI."""

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session

from core.database import get_core_db
from core.security import get_current_user

from . import service
from .dto import InvoiceStampResponse

router = APIRouter()


def _uid(cu: dict) -> str | None:
    return cu.get("sub") or cu.get("id")


@router.post(
    "/invoices/{invoice_id}/stamp",
    response_model=InvoiceStampResponse,
    status_code=status.HTTP_200_OK,
)
def stamp_invoice(
    invoice_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    """Timbra la factura ante el PAC.

    El modo (pruebas o producción) sale de ``invoices.stamping_mode`` y **no se puede pasar
    por aquí**: ni por cuerpo, ni por query, ni por cabecera. Es lo único que separa un timbre
    de prueba de un CFDI con validez fiscal ante el SAT.

    Es idempotente: si la factura ya tiene timbre, lo devuelve sin volver a llamar al PAC.
    """
    return service.stamp_invoice(
        db, invoice_id, current_user["tenant_id"], company_id, _uid(current_user)
    )


@router.get("/invoices/{invoice_id}/stamp", response_model=InvoiceStampResponse)
def get_invoice_stamp(
    invoice_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    """Timbre vigente de la factura."""
    stamp = service.get_stamp(db, invoice_id, current_user["tenant_id"], company_id)
    if not stamp:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="La factura no está timbrada"
        )
    return stamp


@router.get("/invoices/{invoice_id}/stamp/attempts", response_model=list[InvoiceStampResponse])
def list_stamp_attempts(
    invoice_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    """Historial de intentos de timbrado, incluidos los rechazados por el PAC."""
    return service.list_attempts(db, invoice_id, current_user["tenant_id"], company_id)


@router.get("/invoices/{invoice_id}/stamp/attempts/{attempt_id}/xml-url")
def get_stamp_attempt_xml_url(
    invoice_id: int,
    attempt_id: int,
    kind: str = Query(..., pattern="^(request|response)$"),
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    """URL firmada del XML transmitido al PAC (``request``) o del que contestó (``response``)."""
    url = service.get_attempt_xml_url(
        db, invoice_id, attempt_id, kind, current_user["tenant_id"], company_id
    )
    return {"url": url}


@router.get("/invoices/{invoice_id}/stamp/xml-url")
def get_stamp_xml_url(
    invoice_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    """URL firmada para descargar el XML timbrado."""
    url = service.get_stamp_xml_url(db, invoice_id, current_user["tenant_id"], company_id)
    return {"url": url}
