from fastapi import APIRouter, Depends, HTTPException, Query, status

from app.api.deps import require_session
from app.services.tenant_store import (
    InventoryConsumptionWritePayload,
    InventoryProductCreatePayload,
    InventoryProductCodeWritePayload,
    InventorySessionCreatePayload,
    InventorySnapshotCreatePayload,
    InventoryStockWritePayload,
    InventoryTransferWritePayload,
    InventoryWarehouseCreatePayload,
    SessionIdentity,
    get_tenant_store,
)


router = APIRouter()


def _raise_inventory_error(exc: ValueError) -> None:
    detail = str(exc)
    lowered = detail.lower()
    status_code = (
        status.HTTP_403_FORBIDDEN
        if "non puo accedere" in lowered or "superadmin" in lowered
        else status.HTTP_400_BAD_REQUEST
    )
    raise HTTPException(status_code=status_code, detail=detail) from exc


@router.get("/warehouses")
def list_inventory_warehouses(session: SessionIdentity = Depends(require_session)) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_warehouses(session)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/warehouses")
def create_inventory_warehouse(
    payload: InventoryWarehouseCreatePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().create_inventory_warehouse(session, payload)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.patch("/warehouses/{warehouse_id}")
def update_inventory_warehouse(
    warehouse_id: str,
    payload: InventoryWarehouseCreatePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().update_inventory_warehouse(session, warehouse_id, payload)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.delete("/warehouses/{warehouse_id}")
def delete_inventory_warehouse(
    warehouse_id: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().delete_inventory_warehouse(session, warehouse_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/warehouses/{warehouse_id}")
def get_inventory_warehouse_detail(
    warehouse_id: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_warehouse_detail(session, warehouse_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/warehouses/{warehouse_id}/sessions")
def list_inventory_warehouse_sessions(
    warehouse_id: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_warehouse_sessions(session, warehouse_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/warehouses/{warehouse_id}/sessions/{session_id}")
def get_inventory_warehouse_session_detail(
    warehouse_id: str,
    session_id: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_warehouse_session_detail(session, warehouse_id, session_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/warehouses/{warehouse_id}/sessions/{session_id}/load")
def load_inventory_warehouse_session_into_stock(
    warehouse_id: str,
    session_id: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().load_inventory_warehouse_session_into_stock(session, warehouse_id, session_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/warehouses/{warehouse_id}/stock/reset")
def reset_inventory_warehouse_stock(
    warehouse_id: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().reset_inventory_warehouse_stock(session, warehouse_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.delete("/warehouses/{warehouse_id}/sessions/{session_id}")
def delete_inventory_warehouse_session(
    warehouse_id: str,
    session_id: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().delete_inventory_warehouse_session(session, warehouse_id, session_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/warehouses/{warehouse_id}/sessions")
def create_inventory_warehouse_session(
    warehouse_id: str,
    payload: InventorySessionCreatePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().create_inventory_warehouse_session(session, warehouse_id, payload)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/warehouses/{warehouse_id}/consumption")
def get_inventory_warehouse_consumption(
    warehouse_id: str,
    start_session_id: str | None = Query(default=None),
    end_session_id: str | None = Query(default=None),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_warehouse_consumption(
            session,
            warehouse_id,
            start_session_id=start_session_id,
            end_session_id=end_session_id,
        )
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/totals/history")
def list_inventory_totals_history(
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_totals_history(session)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/totals/history/{inventory_date}")
def get_inventory_totals_detail(
    inventory_date: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_totals_detail(session, inventory_date=inventory_date)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/products/search")
def search_inventory_products(
    q: str | None = Query(default=None),
    limit: int = Query(default=20, ge=1, le=100),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().search_inventory_products(session, query=q, limit=limit)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/products/{product_id}/variants")
def list_inventory_product_variants(
    product_id: int,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_product_variants(session, product_id=product_id)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/products")
def create_inventory_product(
    payload: InventoryProductCreatePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().create_inventory_product(session, payload)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.patch("/products/{product_id}/barcode")
def update_inventory_product_code(
    product_id: int,
    payload: InventoryProductCodeWritePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().update_inventory_product_code(session, product_id=product_id, payload=payload)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/warehouses/{warehouse_id}/stock")
def add_inventory_stock(
    warehouse_id: str,
    payload: InventoryStockWritePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().add_inventory_stock(session, warehouse_id, payload)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/transfers")
def transfer_inventory_stock(
    payload: InventoryTransferWritePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().transfer_inventory_stock(session, payload)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions")
def list_inventory_consumptions(
    warehouse_id: str | None = Query(default=None),
    limit: int = Query(default=120, ge=1, le=500),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_consumptions(session, warehouse_id=warehouse_id, limit=limit)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions/days")
def list_inventory_consumption_days(
    year: int | None = Query(default=None, ge=2000, le=2100),
    q: str | None = Query(default=None, max_length=180),
    limit: int = Query(default=366, ge=1, le=1000),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_consumption_days(session, year=year, query=q, limit=limit)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions/years")
def list_inventory_consumption_years(
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_consumption_years(session)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions/totals")
def list_inventory_consumption_product_totals(
    year: int = Query(ge=2000, le=2100),
    q: str | None = Query(default=None, max_length=180),
    limit: int = Query(default=500, ge=1, le=1000),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_consumption_product_totals(
            session,
            year=year,
            query=q,
            limit=limit,
        )
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions/days/{consumption_date}")
def get_inventory_consumption_day_detail(
    consumption_date: str,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_consumption_day_detail(session, consumption_date=consumption_date)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions/trend")
def get_inventory_consumption_product_trend(
    product_name: str = Query(min_length=1, max_length=180),
    supplier_name: str = Query(default="", max_length=180),
    limit: int = Query(default=120, ge=1, le=366),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_consumption_product_trend(
            session,
            product_name=product_name,
            supplier_name=supplier_name,
            limit=limit,
        )
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions/estimate-2025")
def get_inventory_consumption_2025_estimate(
    workdays: int = Query(default=88, ge=1, le=366),
    q: str | None = Query(default=None, max_length=180),
    limit: int = Query(default=500, ge=1, le=1000),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_consumption_2025_estimate(
            session,
            year=2025,
            workdays=workdays,
            query=q,
            limit=limit,
        )
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumptions/stats")
def list_inventory_consumption_product_stats(
    q: str | None = Query(default=None),
    limit: int = Query(default=200, ge=1, le=500),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_consumption_product_stats(session, query=q, limit=limit)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/consumptions")
def create_inventory_consumption(
    payload: InventoryConsumptionWritePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().create_inventory_consumption(session, payload)
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/snapshots")
def list_inventory_snapshots(session: SessionIdentity = Depends(require_session)) -> dict[str, object]:
    try:
        return get_tenant_store().list_inventory_snapshots(session)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.post("/snapshots")
def create_inventory_snapshot(
    payload: InventorySnapshotCreatePayload,
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().create_inventory_snapshot(session, payload)
    except ValueError as exc:
        _raise_inventory_error(exc)


@router.get("/consumption")
def get_inventory_consumption_overview(
    start_snapshot_id: str | None = Query(default=None),
    end_snapshot_id: str | None = Query(default=None),
    session: SessionIdentity = Depends(require_session),
) -> dict[str, object]:
    try:
        return get_tenant_store().get_inventory_consumption_overview(
            session,
            start_snapshot_id=start_snapshot_id,
            end_snapshot_id=end_snapshot_id,
        )
    except KeyError as exc:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=exc.args[0] if exc.args else str(exc)) from exc
    except ValueError as exc:
        _raise_inventory_error(exc)
