import uuid

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

from app.core.database import get_db
from app.core.permissions import deny_vendor, require_permission
from app.core.security import AuthContext, get_auth_context
from app.crud.audit import write_audit_log
from app.crud.base import CRUDBase
from app.crud.portal_menu import check_logo_file
from app.models.identity import Role
from app.schemas.identity import RoleCreate, RoleRead, RoleScope, RoleUpdate

router = APIRouter(prefix="/roles", tags=["roles"])
crud = CRUDBase[Role, RoleCreate, RoleUpdate](Role)


@router.get("", response_model=list[RoleRead])
async def list_roles(
    skip: int = 0,
    limit: int = 100,
    scope: RoleScope | None = None,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("users_roles", "view")),
) -> list[Role]:
    return await crud.list(db, ctx.tenant_id, skip=skip, limit=limit, scope=scope)


@router.get("/{role_id}", response_model=RoleRead)
async def get_role(
    role_id: uuid.UUID,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("users_roles", "view")),
) -> Role:
    return await crud.get(db, ctx.tenant_id, role_id)


@router.post("", response_model=RoleRead, status_code=status.HTTP_201_CREATED)
async def create_role(
    payload: RoleCreate,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("users_roles", "create")),
    __: AuthContext = Depends(deny_vendor()),
) -> Role:
    return await crud.create(db, ctx.tenant_id, payload)


@router.patch("/{role_id}", response_model=RoleRead)
async def update_role(
    role_id: uuid.UUID,
    payload: RoleUpdate,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("users_roles", "edit")),
    __: AuthContext = Depends(deny_vendor()),
) -> Role:
    role = await crud.get(db, ctx.tenant_id, role_id)
    if role.is_system_role and payload.action_matrix is not None:
        raise HTTPException(
            status_code=409,
            detail="The Administrator role's permissions are fixed and cannot be reduced (FR-RBA-005).",
        )
    if payload.theme is not None and role.scope != "portal":
        raise HTTPException(status_code=422, detail="Only portal roles have their own theme — the Studio follows Settings › Appearance.")
    if payload.portal_permissions and role.scope != "portal":
        raise HTTPException(status_code=422, detail="Only portal roles have detailed portal permissions.")
    if payload.menu_settings is not None:
        if role.scope != "portal":
            raise HTTPException(status_code=422, detail="Only portal roles have their own menu settings.")
        if payload.menu_settings.get("logo_file_id"):
            await check_logo_file(db, ctx.tenant_id, uuid.UUID(str(payload.menu_settings["logo_file_id"])))
    updated = await crud.update(db, ctx.tenant_id, role_id, payload)
    await write_audit_log(
        db, ctx.tenant_id, ctx.user_id, "role.permissions_changed", "role", role_id,
        {"fields": list(payload.model_dump(exclude_unset=True).keys())},
    )
    return updated


@router.delete("/{role_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_role(
    role_id: uuid.UUID,
    ctx: AuthContext = Depends(get_auth_context),
    db: AsyncSession = Depends(get_db),
    _: AuthContext = Depends(require_permission("users_roles", "delete")),
    __: AuthContext = Depends(deny_vendor()),
) -> None:
    role = await crud.get(db, ctx.tenant_id, role_id)
    if role.is_system_role:
        raise HTTPException(status_code=409, detail="The Administrator role cannot be deleted (FR-RBA-005).")
    await crud.delete(db, ctx.tenant_id, role_id)
