import os
import uuid
from typing import Any

from fastapi import APIRouter, Depends, HTTPException, Query, UploadFile, 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.menu_item import MenuItem, MenuItemCreate, MenuItemRead, MenuItemUpdate
from app.models.restaurant import Restaurant
from app.services import storage

router = APIRouter(prefix="/menu-items", tags=["menu-items"])


ALLOWED_PHOTO_TYPES = {"image/jpeg", "image/png", "image/webp"}
MAX_PHOTO_BYTES = 5 * 1024 * 1024  # 5 MB


@router.get("/", response_model=list[MenuItemRead])
async def list_menu_items(
    category: str | None = Query(default=None),
    is_active: bool | None = Query(default=None),
    limit: int = Query(default=50, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> list[Any]:
    query = select(MenuItem).where(MenuItem.restaurant_id == restaurant.id)
    if category is not None:
        query = query.where(MenuItem.category == category)
    if is_active is not None:
        query = query.where(MenuItem.is_active == is_active)
    query = query.order_by(MenuItem.sort_order, MenuItem.name).offset(offset).limit(limit)  # type: ignore[arg-type]
    result = await session.execute(query)
    return list(result.scalars().all())


@router.post("/", response_model=MenuItemRead, status_code=status.HTTP_201_CREATED)
async def create_menu_item(
    payload: MenuItemCreate,
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> Any:
    item = MenuItem(**payload.model_dump(), restaurant_id=restaurant.id)
    session.add(item)
    await session.commit()
    await session.refresh(item)
    return item


@router.patch("/{item_id}", response_model=MenuItemRead)
async def update_menu_item(
    item_id: str,
    payload: MenuItemUpdate,
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> Any:
    result = await session.execute(
        select(MenuItem).where(MenuItem.id == item_id, MenuItem.restaurant_id == restaurant.id)
    )
    item = result.scalar_one_or_none()
    if item is None:
        raise HTTPException(status_code=404, detail="Menu item not found")

    for key, value in payload.model_dump(exclude_unset=True).items():
        setattr(item, key, value)

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


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

    # Clean up S3 photo if exists
    if item.photo_url:
        old_key = storage.key_from_url(item.photo_url)
        if old_key:
            storage.delete_file(old_key)

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


@router.post("/{item_id}/photo", response_model=MenuItemRead)
async def upload_menu_item_photo(
    item_id: str,
    file: UploadFile,
    session: AsyncSession = Depends(get_tenant_session),
    restaurant: Restaurant = Depends(get_current_restaurant),
) -> Any:
    if file.content_type not in ALLOWED_PHOTO_TYPES:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail=f"Unsupported image type: {file.content_type}. Allowed: JPEG, PNG, WebP.",
        )

    result = await session.execute(
        select(MenuItem).where(MenuItem.id == item_id, MenuItem.restaurant_id == restaurant.id)
    )
    item = result.scalar_one_or_none()
    if item is None:
        raise HTTPException(status_code=404, detail="Menu item not found")

    data = await file.read()
    if len(data) > MAX_PHOTO_BYTES:
        raise HTTPException(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            detail=f"Photo exceeds maximum size of {MAX_PHOTO_BYTES // (1024 * 1024)} MB.",
        )

    # Remove old photo from S3 if exists
    if item.photo_url:
        old_key = storage.key_from_url(item.photo_url)
        if old_key:
            storage.delete_file(old_key)

    ext = os.path.splitext(file.filename or ".jpg")[1] or ".jpg"
    key = f"menu-items/{item_id}_{uuid.uuid4().hex[:8]}{ext}"
    photo_url = storage.upload_file(data, key, file.content_type or "image/jpeg")

    item.photo_url = photo_url
    session.add(item)
    await session.commit()
    await session.refresh(item)
    return item
