"""Level administration — the permission model as editable data.

Every mutation passes the ACTOR into the kit, which enforces its own guards
(`levels.create` / `levels.edit_permissions`, in-use refusal, the "super admin"
name ban). Scout adds nothing on top except translating `AccountsError` into
the structured error shape; by the seeded defaults only the owner holds the
`levels.*` permissions, and that is deliberate.
"""

from fastapi import APIRouter, Depends, HTTPException, status

from app.models.account import Account
from app.models.schemas import LevelCreate, LevelDef, LevelsOut, LevelUpdate, PermissionInfo
from app.services import levels
from app.services.authz import current_account, require_accounts_admin

router = APIRouter(prefix="/api/levels", tags=["levels"])

_STATUS_FOR = {
    "FORBIDDEN": status.HTTP_403_FORBIDDEN,
    "NOT_ASSIGNABLE": status.HTTP_403_FORBIDDEN,
    "OWNER_IMMUTABLE": status.HTTP_409_CONFLICT,
    "EXISTS": status.HTTP_409_CONFLICT,
    "NO_SUCH_LEVEL": status.HTTP_404_NOT_FOUND,
    "NO_SUCH_MEMBER": status.HTTP_404_NOT_FOUND,
    "NO_SUCH_INSTANCE": status.HTTP_404_NOT_FOUND,
    "BAD_INPUT": status.HTTP_422_UNPROCESSABLE_ENTITY,
}


def _raise(exc: levels.AccountsError) -> None:
    """Surface the kit's refusal verbatim — its codes are the contract."""
    raise HTTPException(
        status_code=_STATUS_FOR.get(exc.code, status.HTTP_403_FORBIDDEN),
        detail={"error_code": exc.code, "summary": str(exc)},
    ) from exc


@router.get("", response_model=LevelsOut)
def list_levels(account: Account = Depends(require_accounts_admin)) -> LevelsOut:
    return LevelsOut(
        levels=[LevelDef(**definition) for definition in levels.level_definitions()],
        known_permissions=[PermissionInfo(**p) for p in levels.permission_catalog()],
        assignable_by_me=levels.assignable_by(account.username),
        can_edit=levels.app_can(account.username, "levels.edit_permissions")
        or levels.is_owner(account.username),
    )


@router.post("", response_model=LevelDef, status_code=status.HTTP_201_CREATED)
def create_level(
    payload: LevelCreate, account: Account = Depends(current_account)
) -> LevelDef:
    try:
        definition = levels.create_level(
            account.username, payload.name, payload.permissions, payload.assignable
        )
    except levels.AccountsError as exc:
        _raise(exc)
    return LevelDef(**definition, in_use_by=0)


@router.patch("/{name}", response_model=LevelDef)
def update_level(
    name: str, payload: LevelUpdate, account: Account = Depends(current_account)
) -> LevelDef:
    current = next((d for d in levels.level_definitions() if d["name"] == name), None)
    if current is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail={"error_code": "NO_SUCH_LEVEL", "summary": f"No level called '{name}'."},
        )
    try:
        definition = levels.update_level(
            account.username,
            name,
            payload.permissions if payload.permissions is not None else current["permissions"],
            payload.assignable if payload.assignable is not None else current["assignable"],
        )
    except levels.AccountsError as exc:
        _raise(exc)
    return LevelDef(**definition, in_use_by=current["in_use_by"])


@router.delete("/{name}", status_code=status.HTTP_204_NO_CONTENT)
def delete_level(name: str, account: Account = Depends(current_account)) -> None:
    try:
        levels.delete_level(account.username, name)
    except levels.AccountsError as exc:
        _raise(exc)
