"""Endpoints del módulo Tarifario."""

from datetime import date

from fastapi import APIRouter, Depends, File, Form, Query, Response, UploadFile, 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 (
    CostRequest,
    CostResult,
    ImportPreview,
    RateBreakDTO,
    RateChargeCreate,
    RateChargeResponse,
    RateChargeUpdate,
    RateLaneCreate,
    RateLaneResponse,
    RateSheetCreate,
    RateSheetResponse,
    RateSheetUpdate,
)

router = APIRouter(prefix="/rate-sheets", tags=["Tarifario"])


def _ctx(current_user: dict):
    return current_user["tenant_id"], current_user.get("sub") or current_user.get("id")


def _sheet_out(db: Session, tenant_id: int, sheet) -> RateSheetResponse:
    out = RateSheetResponse.model_validate(sheet)
    out.lane_count = service.lane_count(db, tenant_id, sheet.id)
    return out


def _lane_out(db: Session, lane) -> RateLaneResponse:
    out = RateLaneResponse.model_validate(lane)
    out.breaks = [RateBreakDTO.model_validate(b) for b in service.breaks_of(db, lane.id)]
    return out


# ---------------- Tarifarios ----------------
@router.get("", response_model=list[RateSheetResponse])
def list_sheets(
    company_id: int = Query(...),
    mode: str | None = Query(None),
    supplier_id: int | None = Query(None),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    sheets = service.list_sheets(db, tenant_id, company_id, mode=mode, supplier_id=supplier_id)
    return [_sheet_out(db, tenant_id, s) for s in sheets]


@router.post("", response_model=RateSheetResponse, status_code=status.HTTP_201_CREATED)
def create_sheet(
    data: RateSheetCreate,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, user_id = _ctx(current_user)
    sheet = service.create_sheet(db, tenant_id, company_id, data, user_id)
    return _sheet_out(db, tenant_id, sheet)


@router.get("/template")
def download_template(
    mode: str = Query(..., description="aereo | maritimo_fcl | maritimo_lcl | terrestre"),
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
):
    content = service.build_template(mode)
    return Response(
        content=content,
        media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        headers={"Content-Disposition": f'attachment; filename="plantilla_tarifario_{mode}.xlsx"'},
    )


@router.post("/import/preview", response_model=ImportPreview)
async def import_preview(
    company_id: int = Query(...),
    mode: str = Form(...),
    file: UploadFile = File(...),
    current_user: dict = Depends(get_current_user),
):
    content = await file.read()
    return service.parse_excel(mode, content)


@router.post("/import", response_model=RateSheetResponse, status_code=status.HTTP_201_CREATED)
async def import_sheet(
    company_id: int = Query(...),
    mode: str = Form(...),
    name: str = Form(...),
    supplier_id: int | None = Form(None),
    currency: str = Form("USD"),
    valid_from: date | None = Form(None),
    valid_to: date | None = Form(None),
    default_origin: str | None = Form(None),
    file: UploadFile = File(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, user_id = _ctx(current_user)
    content = await file.read()
    header = RateSheetCreate(
        mode=mode, name=name, supplier_id=supplier_id, currency=currency,
        valid_from=valid_from, valid_to=valid_to, default_origin=default_origin,
    )
    sheet = service.import_from_excel(db, tenant_id, company_id, mode, content, header, user_id)
    return _sheet_out(db, tenant_id, sheet)


@router.get("/{sheet_id}", response_model=RateSheetResponse)
def get_sheet(
    sheet_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    return _sheet_out(db, tenant_id, service.get_sheet(db, tenant_id, company_id, sheet_id))


@router.patch("/{sheet_id}", response_model=RateSheetResponse)
def update_sheet(
    sheet_id: int,
    data: RateSheetUpdate,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, user_id = _ctx(current_user)
    return _sheet_out(db, tenant_id, service.update_sheet(db, tenant_id, company_id, sheet_id, data, user_id))


@router.delete("/{sheet_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_sheet(
    sheet_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    service.delete_sheet(db, tenant_id, company_id, sheet_id)


# ---------------- Rutas (lanes) ----------------
@router.get("/{sheet_id}/lanes", response_model=list[RateLaneResponse])
def list_lanes(
    sheet_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    service.get_sheet(db, tenant_id, company_id, sheet_id)
    return [_lane_out(db, lane) for lane in service.list_lanes(db, tenant_id, sheet_id)]


@router.post("/{sheet_id}/lanes", response_model=RateLaneResponse, status_code=status.HTTP_201_CREATED)
def create_lane(
    sheet_id: int,
    data: RateLaneCreate,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    lane = service.create_lane(db, tenant_id, company_id, sheet_id, data)
    return _lane_out(db, lane)


@router.delete("/{sheet_id}/lanes/{lane_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_lane(
    sheet_id: int,
    lane_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    service.delete_lane(db, tenant_id, sheet_id, lane_id)


# ---------------- Cargos adicionales ----------------
@router.get("/{sheet_id}/charges", response_model=list[RateChargeResponse])
def list_charges(
    sheet_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    service.get_sheet(db, tenant_id, company_id, sheet_id)
    return service.list_charges(db, tenant_id, sheet_id)


@router.post("/{sheet_id}/charges", response_model=RateChargeResponse, status_code=status.HTTP_201_CREATED)
def create_charge(
    sheet_id: int,
    data: RateChargeCreate,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    return service.create_charge(db, tenant_id, company_id, sheet_id, data)


@router.patch("/{sheet_id}/charges/{charge_id}", response_model=RateChargeResponse)
def update_charge(
    sheet_id: int,
    charge_id: int,
    data: RateChargeUpdate,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    return service.update_charge(db, tenant_id, sheet_id, charge_id, data)


@router.delete("/{sheet_id}/charges/{charge_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_charge(
    sheet_id: int,
    charge_id: int,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    tenant_id, _ = _ctx(current_user)
    service.delete_charge(db, tenant_id, sheet_id, charge_id)


# ---------------- Motor de costeo ----------------
cost_router = APIRouter(tags=["Tarifario"])


@cost_router.post("/rate-quote", response_model=CostResult)
def rate_quote(
    req: CostRequest,
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    """Calcula opciones de costo (por proveedor) para una ruta/carga."""
    tenant_id, _ = _ctx(current_user)
    options = service.quote_cost(db, tenant_id, company_id, req)
    return CostResult(request=req, options=options)


@cost_router.get("/rate-locations")
def rate_locations(
    mode: str = Query(...),
    company_id: int = Query(...),
    current_user: dict = Depends(get_current_user),
    db: Session = Depends(get_core_db),
):
    """Orígenes/destinos cotizables (de los tarifarios activos) para alinear el cotizador."""
    tenant_id, _ = _ctx(current_user)
    return service.lane_locations(db, tenant_id, company_id, mode)
