"""导航菜单 Admin CRUD API — /admin/menus"""
from __future__ import annotations

from typing import Any
from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select

from app.api.deps import get_db, get_admin_user
from app.core.models.user import User
from app.core.models.navigation_menu import NavigationMenu

router = APIRouter(prefix="/admin/menus", tags=["菜单管理"])

# ── Schema ────────────────────────────────────────────────────────────────────

class MenuItemSchema(BaseModel):
    id: str
    label: str
    url: str
    type: str = "custom"        # custom | page | category | brand
    target: str = "_self"       # _self | _blank
    icon: str | None = None
    children: list["MenuItemSchema"] = []

MenuItemSchema.model_rebuild()


class MenuOut(BaseModel):
    id: int
    name: str
    location: str
    is_active: bool
    items: list[Any] = []
    meta: dict[str, Any] = {}

    model_config = {"from_attributes": True}


class MenuCreate(BaseModel):
    name: str
    location: str
    is_active: bool = True
    items: list[Any] = []
    meta: dict[str, Any] = {}


class MenuUpdate(BaseModel):
    name: str | None = None
    location: str | None = None
    is_active: bool | None = None
    items: list[Any] | None = None
    meta: dict[str, Any] | None = None


# ── Helpers ───────────────────────────────────────────────────────────────────

def _to_out(m: NavigationMenu) -> MenuOut:
    return MenuOut(
        id=m.id,
        name=m.name,
        location=m.location,
        is_active=m.is_active,
        items=m.items or [],
        meta=m.meta or {},
    )


async def _get_menu(db: AsyncSession, menu_id: int, tenant_id: int) -> NavigationMenu:
    result = await db.execute(
        select(NavigationMenu).where(
            NavigationMenu.id == menu_id,
            NavigationMenu.tenant_id == tenant_id,
        )
    )
    m = result.scalar_one_or_none()
    if not m:
        raise HTTPException(status_code=404, detail="菜单不存在")
    return m


# ── Routes ────────────────────────────────────────────────────────────────────

@router.get("", response_model=list[MenuOut], summary="获取所有菜单")
async def list_menus(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    result = await db.execute(
        select(NavigationMenu)
        .where(NavigationMenu.tenant_id == current_user.tenant_id)
        .order_by(NavigationMenu.location, NavigationMenu.id)
    )
    return [_to_out(m) for m in result.scalars().all()]


@router.post("", response_model=MenuOut, status_code=201, summary="创建菜单")
async def create_menu(
    body: MenuCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    m = NavigationMenu(
        tenant_id=current_user.tenant_id,
        name=body.name,
        location=body.location,
        is_active=body.is_active,
        items=body.items,
    )
    db.add(m)
    await db.commit()
    await db.refresh(m)
    return _to_out(m)


@router.get("/{menu_id}", response_model=MenuOut, summary="获取单个菜单")
async def get_menu(
    menu_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    return _to_out(await _get_menu(db, menu_id, current_user.tenant_id))


@router.put("/{menu_id}", response_model=MenuOut, summary="更新菜单（含菜单项）")
async def update_menu(
    menu_id: int,
    body: MenuUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    m = await _get_menu(db, menu_id, current_user.tenant_id)
    data = body.model_dump(exclude_unset=True)
    for k, v in data.items():
        setattr(m, k, v)
    await db.commit()
    await db.refresh(m)
    return _to_out(m)


@router.delete("/{menu_id}", status_code=204, summary="删除菜单")
async def delete_menu(
    menu_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_admin_user),
):
    m = await _get_menu(db, menu_id, current_user.tenant_id)
    await db.delete(m)
    await db.commit()
