"""
Permission endpoints:
  GET  /permissions              → all users + their module access matrix (admin only)
  PUT  /permissions/{user_id}    → set modules list for a user (admin only)
  GET  /me/permissions           → current user's accessible modules (any authenticated user)
"""
from typing import List
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete

from app.database import get_db
from app.models.user import User
from app.models.user_permission import UserPermission, ALL_MODULES
from app.deps import get_current_user, require_role
from pydantic import BaseModel

router = APIRouter(tags=["permissions"])
admin_only = require_role("admin")


# ── Schemas ──────────────────────────────────────────────────────────────────

class UserPermissionRow(BaseModel):
    user_id: int
    username: str
    role: str
    modules: List[str]          # list of modules the user CAN access

class PermissionMatrix(BaseModel):
    users: List[UserPermissionRow]
    all_modules: List[str]

class SetPermissionsBody(BaseModel):
    modules: List[str]          # modules to grant; everything else is revoked


# ── Helpers ──────────────────────────────────────────────────────────────────

async def _get_user_modules(user_id: int, db: AsyncSession) -> List[str]:
    result = await db.execute(
        select(UserPermission.module)
        .where(UserPermission.user_id == user_id, UserPermission.can_access == True)  # noqa: E712
    )
    return result.scalars().all()


# ── Routes ───────────────────────────────────────────────────────────────────

@router.get("/permissions", response_model=PermissionMatrix)
async def get_permission_matrix(
    db: AsyncSession = Depends(get_db),
    _: User = Depends(admin_only),
):
    users_result = await db.execute(select(User).where(User.is_active == True).order_by(User.id))  # noqa: E712
    users = users_result.scalars().all()

    rows = []
    for u in users:
        if u.role == "admin":
            # admin always has full access
            modules = ALL_MODULES[:]
        else:
            modules = await _get_user_modules(u.id, db)
        rows.append(UserPermissionRow(user_id=u.id, username=u.username, role=u.role, modules=modules))

    return PermissionMatrix(users=rows, all_modules=ALL_MODULES)


@router.put("/permissions/{user_id}", response_model=UserPermissionRow)
async def set_user_permissions(
    user_id: int,
    body: SetPermissionsBody,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(admin_only),
):
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalar_one_or_none()
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    if user.role == "admin":
        raise HTTPException(status_code=400, detail="Cannot restrict admin permissions")

    # Validate modules
    invalid = [m for m in body.modules if m not in ALL_MODULES]
    if invalid:
        raise HTTPException(status_code=422, detail=f"Unknown modules: {invalid}")

    # Replace all permissions for this user
    await db.execute(delete(UserPermission).where(UserPermission.user_id == user_id))
    for module in ALL_MODULES:
        db.add(UserPermission(
            user_id=user_id,
            module=module,
            can_access=module in body.modules,
        ))
    await db.commit()

    return UserPermissionRow(user_id=user.id, username=user.username, role=user.role, modules=body.modules)


@router.get("/me/permissions", response_model=List[str])
async def get_my_permissions(
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user),
):
    """Returns list of module names the current user can access."""
    if current_user.role == "admin":
        return ALL_MODULES[:]

    modules = await _get_user_modules(current_user.id, db)
    # If user has no rows yet → grant default (tasks + letters)
    if not modules:
        return ["tasks", "letters"]
    return modules
