"""
Authorizations Router — API endpoints for the authorizations report (PRD-009-HWRPT).

Routes:
  GET  /authorizations/summary                             — top-N customer summaries
  GET  /authorizations/export                              — streaming CSV export
  GET  /authorizations                                     — paginated list with filters
  GET  /authorizations/{authorization_id}                  — full detail view
  GET  /authorizations/{authorization_id}/pdf              — full detail PDF export
  PATCH /authorizations/{authorization_id}/expire          — expire an authorization
  POST  /authorizations/{authorization_id}/request-payment-update — request PM update
"""
from typing import Optional, Annotated

from fastapi import APIRouter, Depends, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from datetime import datetime

from src.core.database import get_session
from src.apps.auth.utils.auth import get_current_merchant
from src.apps.authorizations import services
from src.apps.authorizations.schemas.authorization_list import (
    AuthorizationListResponse,
    AuthorizationSummaryResponse,
)
from src.apps.authorizations.schemas.authorization_detail import (
    AuthorizationAssociationsResponse,
    AuthorizationDetailResponse,
    AuthorizationHistoryResponse,
    AuthorizationInvoicesResponse,
    AuthorizationProofResponse,
    AuthorizationTransactionsResponse,
    ExpireAuthorizationResponse,
    RequestPaymentUpdateRequest,
    RequestPaymentUpdateResponse,
)

router = APIRouter(tags=["AUTHORIZATIONS"])


@router.get(
    "/{authorization_id}/pdf",
    summary="Export Authorization Detail PDF",
    description=(
        "Generate and stream a multi-page PDF for the full authorization detail, "
        "mirroring the on-screen layout (header, detail grid, proof, history, associations)."
    ),
)
async def export_authorization_pdf(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> StreamingResponse:
    pdf_bytes = services.generate_authorization_pdf(
        db=db,
        authorization_id=authorization_id,
        merchant_id=merchant.id,
        merchant=merchant,
    )
    filename = f"{authorization_id}_detail.pdf"
    return StreamingResponse(
        iter([pdf_bytes]),
        media_type="application/pdf",
        headers={"Content-Disposition": f'attachment; filename="{filename}"'},
    )


@router.get(
    "/summary",
    response_model=AuthorizationSummaryResponse,
    summary="Authorization Summary",
    description="Return top-N customer account summaries by amount and frequency.",
)
async def get_authorization_summary(
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationSummaryResponse:
    return services.get_summary(db=db, merchant_id=merchant.id)


@router.get(
    "/export",
    summary="Export Authorizations CSV",
    description="Stream all matching authorizations as a CSV file download.",
)
async def export_authorizations(
    status: Optional[str] = Query(None, description="Filter by authorization status"),
    authorization_type: Optional[str] = Query(None, description="Filter by authorization type"),
    date_from: Optional[datetime] = Query(None, description="Filter: created_at >= date_from"),
    date_to: Optional[datetime] = Query(None, description="Filter: created_at <= date_to"),
    search: Optional[str] = Query(None, max_length=200, description="Search by authorization_id or customer name"),
    amount_min: Optional[float] = Query(None, ge=0, description="Minimum payment request amount"),
    amount_max: Optional[float] = Query(None, ge=0, description="Maximum payment request amount"),
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> StreamingResponse:
    return services.export_csv(
        db=db,
        merchant_id=merchant.id,
        status=status,
        authorization_type=authorization_type,
        date_from=date_from,
        date_to=date_to,
        search=search,
        amount_min=amount_min,
        amount_max=amount_max,
    )


@router.get(
    "",
    response_model=AuthorizationListResponse,
    summary="List Authorizations",
    description="Paginated list of authorizations for the authenticated merchant.",
)
async def list_authorizations(
    status: Optional[str] = Query(None, description="Filter by status (PENDING, ACTIVE, EXPIRED, SUPERSEDED)"),
    authorization_type: Optional[str] = Query(None, description="Filter by type (CHECKBOX, SIGN, SMS)"),
    date_from: Optional[datetime] = Query(None, description="Filter: created_at >= date_from"),
    date_to: Optional[datetime] = Query(None, description="Filter: created_at <= date_to"),
    search: Optional[str] = Query(None, max_length=200, description="Search authorization_id or customer name/email"),
    amount_min: Optional[float] = Query(None, ge=0, description="Minimum payment request amount"),
    amount_max: Optional[float] = Query(None, ge=0, description="Maximum payment request amount"),
    sort_by: str = Query("created_at", max_length=50, description="Sort field (created_at | authorization_date | status)"),
    sort_desc: bool = Query(True, description="Sort descending when True"),
    page: int = Query(1, ge=1, description="Page number (1-indexed)"),
    per_page: int = Query(20, ge=1, le=100, description="Items per page"),
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationListResponse:
    return services.list_authorizations(
        db=db,
        merchant_id=merchant.id,
        status=status,
        authorization_type=authorization_type,
        date_from=date_from,
        date_to=date_to,
        search=search,
        amount_min=amount_min,
        amount_max=amount_max,
        sort_by=sort_by,
        sort_desc=sort_desc,
        page=page,
        per_page=per_page,
    )


@router.get(
    "/{authorization_id}",
    response_model=AuthorizationDetailResponse,
    summary="Get Authorization Detail",
    description="Full detail view for a single authorization including proof, HPP session, and history.",
)
async def get_authorization_detail(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationDetailResponse:
    return services.get_authorization_detail(
        db=db,
        authorization_id=authorization_id,
        merchant_id=merchant.id,
    )


@router.get(
    "/{authorization_id}/proof",
    response_model=AuthorizationProofResponse,
    summary="Get Authorization Proof",
    description="Return the proof-of-authorization sub-section (signature, checkbox, SMS).",
)
async def get_authorization_proof(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationProofResponse:
    return services.get_authorization_proof(
        db=db, authorization_id=authorization_id, merchant_id=merchant.id,
    )


@router.get(
    "/{authorization_id}/history",
    response_model=AuthorizationHistoryResponse,
    summary="Get Authorization History",
    description="Return the chronological event timeline for an authorization.",
)
async def get_authorization_history(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationHistoryResponse:
    return services.get_authorization_history(
        db=db, authorization_id=authorization_id, merchant_id=merchant.id,
    )


@router.get(
    "/{authorization_id}/associations",
    response_model=AuthorizationAssociationsResponse,
    summary="Get Authorization Associations",
    description="Return invoices and transactions linked to this authorization via payment_request_id.",
)
async def get_authorization_associations(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationAssociationsResponse:
    return services.get_authorization_associations(
        db=db, authorization_id=authorization_id, merchant_id=merchant.id,
    )


@router.get(
    "/{authorization_id}/invoices",
    response_model=AuthorizationInvoicesResponse,
    summary="Get Authorization Invoices",
    description="Return invoices linked to this authorization via payment_request_id.",
)
async def get_authorization_invoices(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationInvoicesResponse:
    return services.get_authorization_invoices(
        db=db, authorization_id=authorization_id, merchant_id=merchant.id,
    )


@router.get(
    "/{authorization_id}/transactions",
    response_model=AuthorizationTransactionsResponse,
    summary="Get Authorization Transactions",
    description="Return transactions linked to this authorization via payment_request_id.",
)
async def get_authorization_transactions(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> AuthorizationTransactionsResponse:
    return services.get_authorization_transactions(
        db=db, authorization_id=authorization_id, merchant_id=merchant.id,
    )


@router.patch(
    "/{authorization_id}/expire",
    response_model=ExpireAuthorizationResponse,
    summary="Expire Authorization",
    description="Manually transition an authorization to EXPIRED status. Returns 409 if already terminal.",
)
async def expire_authorization(
    authorization_id: str,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> ExpireAuthorizationResponse:
    return services.expire_authorization(
        db=db,
        authorization_id=authorization_id,
        merchant_id=merchant.id,
    )


@router.post(
    "/{authorization_id}/request-payment-update",
    response_model=RequestPaymentUpdateResponse,
    summary="Request Payment Method Update",
    description=(
        "Generate a payment-method update token and dispatch notifications "
        "to the specified contacts via the specified channels."
    ),
)
async def request_payment_update(
    authorization_id: str,
    body: RequestPaymentUpdateRequest,
    db: Session = Depends(get_session),
    merchant=Depends(get_current_merchant),
) -> RequestPaymentUpdateResponse:
    return services.request_payment_method_update(
        db=db,
        authorization_id=authorization_id,
        merchant_id=merchant.id,
        contact_ids=body.contact_ids,
        channels=body.channels,
        note=body.note,
    )
