from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.models import TenantRole, User
from app.core.security import get_permission_catalog, require_admin

router = APIRouter(prefix="/api/roles", tags=["roles"], dependencies=[Depends(require_admin)])


class RolePayload(BaseModel):
    name: str = Field(min_length=1, max_length=100)
    permissions: list[str] = Field(default_factory=list)


class RoleResponse(RolePayload):
    id: int

    class Config:
        from_attributes = True


def _clean_permissions(values: list[str]) -> list[str]:
    allowed = set(get_permission_catalog())
    return sorted({value.strip() for value in values if value.strip() in allowed})


@router.get("", response_model=list[RoleResponse])
def list_roles(current_user: User = Depends(require_admin), db: Session = Depends(get_db)):
    return [RoleResponse(id=row.id, name=row.name, permissions=row.permissions_json) for row in db.execute(select(TenantRole).where(TenantRole.tenant_id == current_user.tenant_id).order_by(TenantRole.name)).scalars()]


@router.post("", response_model=RoleResponse, status_code=status.HTTP_201_CREATED)
def create_role(data: RolePayload, current_user: User = Depends(require_admin), db: Session = Depends(get_db)):
    role = TenantRole(tenant_id=current_user.tenant_id, name=data.name.strip(), permissions_json=_clean_permissions(data.permissions))
    db.add(role)
    db.commit()
    db.refresh(role)
    return RoleResponse(id=role.id, name=role.name, permissions=role.permissions_json)


@router.put("/{role_id}", response_model=RoleResponse)
def update_role(role_id: int, data: RolePayload, current_user: User = Depends(require_admin), db: Session = Depends(get_db)):
    role = db.execute(select(TenantRole).where(TenantRole.id == role_id, TenantRole.tenant_id == current_user.tenant_id)).scalar_one_or_none()
    if role is None:
        raise HTTPException(status_code=404, detail="Role not found")
    role.name, role.permissions_json = data.name.strip(), _clean_permissions(data.permissions)
    db.commit()
    return RoleResponse(id=role.id, name=role.name, permissions=role.permissions_json)


@router.delete("/{role_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_role(role_id: int, current_user: User = Depends(require_admin), db: Session = Depends(get_db)):
    role = db.execute(select(TenantRole).where(TenantRole.id == role_id, TenantRole.tenant_id == current_user.tenant_id)).scalar_one_or_none()
    if role is None:
        raise HTTPException(status_code=404, detail="Role not found")
    if db.scalar(select(User.id).where(User.tenant_role_id == role.id)):
        raise HTTPException(status_code=400, detail="Role is assigned to a user")
    db.delete(role)
    db.commit()
