
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from app.api import deps
from app.api.permissions import require_platform_admin
from app.crud.menu import menu as crud_menu
from app.crud.role import role as crud_role
from app.crud.user_role import user_role as crud_user_role
from app.models.user import User
from app.schemas.menu import MenuCreate, MenuResponse, MenuTree, MenuUpdate
from common_logging import get_logger

router = APIRouter()
logger = get_logger(__name__)


def build_menu_tree(menus: list, parent_id: int = None) -> list[MenuTree]:
    tree = []
    for menu in menus:
        if menu.parent_id == parent_id:
            menu_dict = MenuTree.model_validate(menu)
            menu_dict.children = build_menu_tree(menus, menu.id)
            tree.append(menu_dict)
    return tree


@router.get("/", response_model=list[MenuResponse])
def get_menus(
    skip: int = 0,
    limit: int = 100,
    db: Session = Depends(deps.get_db_without_tenant),
    current_user: User = Depends(deps.get_current_user),
):
    menus = crud_menu.get_multi(db, skip=skip, limit=limit)
    return menus


@router.get("/tree", response_model=list[MenuTree])
def get_menu_tree(
    db: Session = Depends(deps.get_db_without_tenant),
    current_user: User = Depends(deps.get_current_user),
):
    menus = crud_menu.get_all_active(db)
    tree = build_menu_tree(menus)
    return tree


@router.get("/my", response_model=list[MenuTree])
def get_my_menus(
    db: Session = Depends(deps.get_db_without_tenant),
    current_user: User = Depends(deps.get_current_user),
):
    user_roles = crud_user_role.get_user_roles(db, user_id=current_user.id)
    if not user_roles:
        return []
    menu_ids = set()
    for role in user_roles:
        role_menu_ids = crud_role.get_menus(db, role_id=role.id)
        menu_ids.update(role_menu_ids)
    if not menu_ids:
        return []
    all_menus = crud_menu.get_all_active(db)
    user_menus = [m for m in all_menus if m.id in menu_ids]
    tree = build_menu_tree(user_menus)
    return tree


@router.post("/", response_model=MenuResponse, status_code=status.HTTP_201_CREATED)
def create_menu(
    menu_in: MenuCreate,
    db: Session = Depends(deps.get_db_without_tenant),
    current_user: User = Depends(require_platform_admin()),
):
    existing = crud_menu.get_by_code(db, code=menu_in.code)
    if existing:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="Menu with this code already exists"
        )
    menu = crud_menu.create(db, obj_in=menu_in, created_by=current_user.id)
    logger.bind(user_id=current_user.id, menu_id=menu.id).info("Menu created")
    return menu


@router.put("/{menu_id}", response_model=MenuResponse)
def update_menu(
    menu_id: int,
    menu_in: MenuUpdate,
    db: Session = Depends(deps.get_db_without_tenant),
    current_user: User = Depends(require_platform_admin()),
):
    menu = crud_menu.get(db, id=menu_id)
    if not menu:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Menu not found")
    menu = crud_menu.update(db, db_obj=menu, obj_in=menu_in)
    logger.bind(user_id=current_user.id, menu_id=menu_id).info("Menu updated")
    return menu


@router.delete("/{menu_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_menu(
    menu_id: int,
    db: Session = Depends(deps.get_db_without_tenant),
    current_user: User = Depends(require_platform_admin()),
):
    menu = crud_menu.get(db, id=menu_id)
    if not menu:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Menu not found")
    crud_menu.remove(db, id=menu_id)
    logger.bind(user_id=current_user.id, menu_id=menu_id).info("Menu deleted")
    return None
