"""Roles router — endpoints for role management and permission matrices."""

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

from app.core.database import get_db
from app.dependencies import get_current_user
from app.models.user import User
from app.schemas.role import PermissionsUpdate, RoleCreate, RolePermissionResponse, RoleResponse, RoleUpdate
from app.services import role_service


def _service_error(e: ValueError | PermissionError) -> HTTPException:
    """Convert service-layer ValueError → 404 and PermissionError → 403."""
    if isinstance(e, PermissionError):
        return HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e))
    return HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))


router = APIRouter()


@router.get("", response_model=dict)
async def list_roles(
    spbu_id: int | None = None,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> dict:
    """Return all roles, optionally scoped to a specific SPBU (includes global roles)."""
    roles = await role_service.list_roles(db, spbu_id)
    return {"data": [RoleResponse.model_validate(r) for r in roles]}


@router.post("", response_model=dict, status_code=status.HTTP_201_CREATED)
async def create_role(
    data: RoleCreate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> dict:
    """Create a new role. Super Admin can create global roles; SPBU Admin only for their own SPBU."""
    try:
        role = await role_service.create_role(db, data, current_user)
    except PermissionError as e:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=str(e))
    return {"data": RoleResponse.model_validate(role), "message": "Role berhasil dibuat"}


@router.get("/{role_id}", response_model=dict)
async def get_role(
    role_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> dict:
    """Return details for a single role including its permissions."""
    try:
        role = await role_service.get_role(db, role_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
    return {"data": RoleResponse.model_validate(role)}


@router.patch("/{role_id}", response_model=dict)
async def update_role(
    role_id: int,
    data: RoleUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> dict:
    """Update scalar fields on a role."""
    try:
        role = await role_service.update_role(db, role_id, data, current_user)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {"data": RoleResponse.model_validate(role), "message": "Role berhasil diupdate"}


@router.delete("/{role_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_role(
    role_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> None:
    """Permanently delete a role."""
    try:
        await role_service.delete_role(db, role_id, current_user)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)


@router.get("/{role_id}/permissions", response_model=dict)
async def get_permissions(
    role_id: int,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> dict:
    """Return all permission entries for a given role."""
    try:
        permissions = await role_service.get_permissions(db, role_id)
    except ValueError as e:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
    return {"data": [RolePermissionResponse.model_validate(p) for p in permissions]}


@router.put("/{role_id}/permissions", response_model=dict)
async def set_permissions(
    role_id: int,
    data: PermissionsUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
) -> dict:
    """Replace the full permission matrix for a role atomically."""
    try:
        permissions = await role_service.set_permissions(db, role_id, data.permissions, current_user)
    except (ValueError, PermissionError) as e:
        raise _service_error(e)
    return {
        "data": [RolePermissionResponse.model_validate(p) for p in permissions],
        "message": "Permissions berhasil disimpan",
    }
