from typing import Any

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select

from app.auth.tenant import get_current_restaurant, get_tenant_session
from app.models.restaurant import Restaurant
from app.models.table import FloorTable
from app.models.zone import Zone
from app.schemas.zone import ZoneCreate, ZoneRead, ZoneUpdate

router = APIRouter(prefix="/zones", tags=["zones"])


@router.get("/", response_model=list[ZoneRead])
async def list_zones(
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> list[Any]:
    result = await session.execute(
        select(Zone).where(Zone.restaurant_id == restaurant.id).order_by(Zone.display_order)  # type: ignore[arg-type]
    )
    return list(result.scalars().all())


@router.post("/", response_model=ZoneRead, status_code=status.HTTP_201_CREATED)
async def create_zone(
    payload: ZoneCreate,
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> Any:
    zone = Zone(**payload.model_dump(), restaurant_id=restaurant.id)
    session.add(zone)
    await session.commit()
    await session.refresh(zone)
    return zone


@router.put("/{zone_id}", response_model=ZoneRead)
async def update_zone(
    zone_id: str,
    payload: ZoneUpdate,
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> Any:
    result = await session.execute(
        select(Zone).where(Zone.id == zone_id, Zone.restaurant_id == restaurant.id)
    )
    zone = result.scalar_one_or_none()
    if zone is None:
        raise HTTPException(status_code=404, detail="Zone not found")

    for key, value in payload.model_dump().items():
        setattr(zone, key, value)

    session.add(zone)
    await session.commit()
    await session.refresh(zone)
    return zone


@router.delete("/{zone_id}", status_code=status.HTTP_200_OK)
async def delete_zone(
    zone_id: str,
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> dict[str, str]:
    result = await session.execute(
        select(Zone).where(Zone.id == zone_id, Zone.restaurant_id == restaurant.id)
    )
    zone = result.scalar_one_or_none()
    if zone is None:
        raise HTTPException(status_code=404, detail="Zone not found")

    # Reject if zone still contains tables
    table_result = await session.execute(
        select(FloorTable.id).where(FloorTable.zone_id == zone_id).limit(1)
    )
    if table_result.scalar_one_or_none() is not None:
        raise HTTPException(
            status_code=status.HTTP_409_CONFLICT,
            detail="Cannot delete zone that contains tables. Move or delete tables first.",
        )

    await session.delete(zone)
    await session.commit()
    return {"status": "deleted"}
