from typing import List, Optional

from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.dependencies import get_current_company_id
from app.schemas.landed_cost import LandedCostCreate, LandedCostResponse
from app.services.landed_cost_service import LandedCostService
from app.utils.logger import get_logger

logger = get_logger(__name__)

router = APIRouter()


def _to_response(lc) -> LandedCostResponse:
    resp = LandedCostResponse.model_validate(lc)
    if lc.purchase:
        resp.purchase_reference = lc.purchase.reference or lc.purchase.id
    if lc.supplier:
        resp.supplier_name = lc.supplier.name
    return resp


@router.get("/", response_model=List[LandedCostResponse])
@router.get("", response_model=List[LandedCostResponse])
def list_landed_costs(
    skip: int = 0,
    limit: int = 200,
    db: Session = Depends(get_db),
    company_id: Optional[str] = Depends(get_current_company_id),
):
    """List landed cost documents for the current company."""
    service = LandedCostService(db)
    records = service.list_landed_costs(company_id=company_id, skip=skip, limit=limit)
    return [_to_response(lc) for lc in records]


@router.get("/{landed_cost_id}", response_model=LandedCostResponse)
def get_landed_cost(
    landed_cost_id: str,
    db: Session = Depends(get_db),
    company_id: Optional[str] = Depends(get_current_company_id),
):
    """Get a single landed cost document."""
    service = LandedCostService(db)
    landed_cost = service.get_landed_cost(landed_cost_id, company_id=company_id)
    if not landed_cost:
        raise HTTPException(status_code=404, detail="Landed cost not found")
    return _to_response(landed_cost)


@router.post("/", response_model=LandedCostResponse)
def create_landed_cost(
    landed_cost: LandedCostCreate,
    db: Session = Depends(get_db),
):
    """
    Create a new Landed Cost document.
    """
    service = LandedCostService(db)
    try:
        created = service.create_landed_cost(landed_cost)
        return _to_response(created)
    except IntegrityError as e:
        db.rollback()
        error_msg = str(e.orig)
        if "duplicate key" in error_msg.lower() or "unique constraint" in error_msg.lower():
            if "reference" in error_msg:
                raise HTTPException(
                    status_code=400,
                    detail="A landed cost with this reference already exists",
                )
            raise HTTPException(
                status_code=400,
                detail="A landed cost with this value already exists. Please ensure unique fields are different.",
            )
        raise HTTPException(status_code=400, detail=f"Database constraint violation: {error_msg}")
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        db.rollback()
        logger.exception("Error creating landed cost")
        raise HTTPException(status_code=500, detail=f"Error creating landed cost: {str(e)}")


@router.post("/{landed_cost_id}/allocate", status_code=200)
def allocate_landed_cost(
    landed_cost_id: str,
    db: Session = Depends(get_db),
    company_id: Optional[str] = Depends(get_current_company_id),
):
    """
    Allocate landed costs to the associated purchase items.
    """
    service = LandedCostService(db)
    landed_cost = service.get_landed_cost(landed_cost_id, company_id=company_id)
    if not landed_cost:
        raise HTTPException(status_code=404, detail="Landed cost not found")
    try:
        service.allocate_landed_cost(landed_cost_id)
        return {"message": "Landed costs allocated successfully."}
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
