from datetime import date
from typing import Annotated, Any
from uuid import UUID

from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

from app.auth.deps import CurrentUser, current_user
from app.db import get_session
from app.services.contracts import contracts_summary

router = APIRouter(prefix="/companies/{company_id}/contracts", tags=["contracts"])


# Server-computed status:
#   closed  — close_date explicitly recorded
#   expired — no close_date but signing_date + execution_days is in the past
#   active  — otherwise (in-flight or indefinite)
# Expressed as a SQL CASE so we can ORDER BY / filter on it cheaply.
_STATUS_SQL = """
  CASE
    WHEN close_date IS NOT NULL THEN 'closed'
    WHEN signing_date IS NOT NULL
     AND execution_days IS NOT NULL
     AND signing_date + (execution_days || ' days')::interval < CURRENT_DATE
      THEN 'expired'
    ELSE 'active'
  END
"""


@router.get("/summary")
async def company_contracts_summary(
    company_id: UUID,
    session: Annotated[AsyncSession, Depends(get_session)],
    _user: Annotated[CurrentUser, Depends(current_user)],
) -> dict[str, Any]:
    return await contracts_summary(session, str(company_id))


@router.get("")
async def list_company_contracts(
    company_id: UUID,
    session: Annotated[AsyncSession, Depends(get_session)],
    _user: Annotated[CurrentUser, Depends(current_user)],
    role: str | None = Query(default="supplier", pattern="^(supplier|awarding|all)$"),
    year: int | None = None,
    current_status: str | None = Query(
        default=None, pattern="^(active|expired|closed)$"
    ),
    page: int = Query(default=1, ge=1),
    page_size: int = Query(default=15, ge=1, le=200),
) -> dict[str, Any]:
    where: list[str] = ["company_id = :cid"]
    params: dict[str, Any] = {"cid": str(company_id)}
    if role and role != "all":
        where.append("role = :role")
        params["role"] = role
    if year:
        where.append("EXTRACT(YEAR FROM coalesce(signing_date, publication_date)) = :yr")
        params["yr"] = year
    if current_status:
        where.append(f"{_STATUS_SQL} = :st")
        params["st"] = current_status
    where_sql = "WHERE " + " AND ".join(where)
    total = (
        await session.execute(
            text(f"SELECT count(*) FROM public_contracts {where_sql}"),
            params,
        )
    ).scalar_one()
    params["limit"] = page_size
    params["offset"] = (page - 1) * page_size
    rows = (
        await session.execute(
            text(
                f"""
                SELECT id::text, external_id, role, title,
                       awarding_entity_name, awarding_entity_nif,
                       supplier_names, supplier_nifs,
                       contract_price, base_price, actual_price,
                       publication_date, signing_date, close_date,
                       execution_days, procedure_type, cpv_codes,
                       district_code, municipality_code,
                       {_STATUS_SQL} AS current_status,
                       CASE
                         WHEN signing_date IS NOT NULL AND execution_days IS NOT NULL
                         THEN signing_date + (execution_days || ' days')::interval
                       END AS expected_end_date
                FROM public_contracts
                {where_sql}
                ORDER BY signing_date DESC NULLS LAST, publication_date DESC NULLS LAST
                LIMIT :limit OFFSET :offset
                """
            ),
            params,
        )
    ).all()
    items = [
        {
            "id": r[0], "external_id": r[1], "role": r[2], "title": r[3],
            "awarding_entity_name": r[4], "awarding_entity_nif": r[5],
            "supplier_names": list(r[6] or []), "supplier_nifs": list(r[7] or []),
            "contract_price": float(r[8]) if r[8] is not None else None,
            "base_price": float(r[9]) if r[9] is not None else None,
            "actual_price": float(r[10]) if r[10] is not None else None,
            "publication_date": r[11], "signing_date": r[12], "close_date": r[13],
            "execution_days": r[14], "procedure_type": r[15],
            "cpv_codes": list(r[16] or []),
            "district_code": r[17], "municipality_code": r[18],
            "current_status": r[19],
            "expected_end_date": r[20].date() if r[20] is not None else None,
        }
        for r in rows
    ]
    return {
        "items": items, "total": int(total), "page": page, "page_size": page_size,
    }


@router.get("/{contract_id}")
async def get_contract_detail(
    company_id: UUID,
    contract_id: UUID,
    session: Annotated[AsyncSession, Depends(get_session)],
    _user: Annotated[CurrentUser, Depends(current_user)],
) -> dict[str, Any]:
    """Single contract with the full IMPIC payload for the modal detail view."""
    row = (
        await session.execute(
            text(
                f"""
                SELECT id::text, external_id, role, title,
                       awarding_entity_name, awarding_entity_nif,
                       supplier_names, supplier_nifs,
                       contract_price, base_price, actual_price,
                       publication_date, signing_date, close_date,
                       execution_days, procedure_type, cpv_codes,
                       district_code, municipality_code,
                       raw_json, source,
                       {_STATUS_SQL} AS current_status,
                       CASE
                         WHEN signing_date IS NOT NULL AND execution_days IS NOT NULL
                         THEN signing_date + (execution_days || ' days')::interval
                       END AS expected_end_date
                FROM public_contracts
                WHERE id = :id AND company_id = :cid
                """
            ),
            {"id": str(contract_id), "cid": str(company_id)},
        )
    ).first()
    if not row:
        raise HTTPException(status.HTTP_404_NOT_FOUND)
    return {
        "id": row[0], "external_id": row[1], "role": row[2], "title": row[3],
        "awarding_entity_name": row[4], "awarding_entity_nif": row[5],
        "supplier_names": list(row[6] or []), "supplier_nifs": list(row[7] or []),
        "contract_price": float(row[8]) if row[8] is not None else None,
        "base_price": float(row[9]) if row[9] is not None else None,
        "actual_price": float(row[10]) if row[10] is not None else None,
        "publication_date": row[11], "signing_date": row[12], "close_date": row[13],
        "execution_days": row[14], "procedure_type": row[15],
        "cpv_codes": list(row[16] or []),
        "district_code": row[17], "municipality_code": row[18],
        "raw": row[19], "source": row[20],
        "current_status": row[21],
        "expected_end_date": row[22].date() if row[22] is not None else None,
    }
