"""Role management service."""

from __future__ import annotations

import uuid
from datetime import UTC, datetime
from typing import Any

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.role import Role


class RoleService:
    """Handles role CRUD operations."""

    async def list_roles(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
    ) -> list[dict[str, Any]]:
        """List all roles in a tenant."""
        q = select(Role).where(Role.tenant_id == tenant_id, Role.deleted_at.is_(None))
        result = await db.execute(q)
        roles = result.scalars().all()
        return [self._role_to_dict(r) for r in roles]

    async def create_role(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        name: str,
        permissions: dict[str, Any],
        denied_permissions: list[str] | None = None,
        field_permissions: dict[str, Any] | None = None,
    ) -> Role:
        """Create a new custom role."""
        role = Role(
            tenant_id=tenant_id,
            name=name,
            permissions=permissions,
            denied_permissions=denied_permissions or [],
            field_permissions=field_permissions or {},
        )
        db.add(role)
        await db.flush()
        return role

    async def update_role(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        role_id: uuid.UUID,
        name: str | None = None,
        permissions: dict[str, Any] | None = None,
        denied_permissions: list[str] | None = None,
        field_permissions: dict[str, Any] | None = None,
    ) -> Role | None:
        """Update a role. Increments permission_version on permission changes."""
        q = select(Role).where(
            Role.id == role_id,
            Role.tenant_id == tenant_id,
            Role.deleted_at.is_(None),
        )
        result = await db.execute(q)
        role = result.scalar_one_or_none()
        if role is None:
            return None

        version_bump = False
        if name is not None:
            role.name = name
        if permissions is not None:
            role.permissions = permissions
            version_bump = True
        if denied_permissions is not None:
            role.denied_permissions = denied_permissions
            version_bump = True
        if field_permissions is not None:
            role.field_permissions = field_permissions
            version_bump = True

        if version_bump:
            role.permission_version += 1

        await db.flush()
        return role

    async def delete_role(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        role_id: uuid.UUID,
    ) -> bool:
        """Soft-delete a role."""
        q = select(Role).where(
            Role.id == role_id,
            Role.tenant_id == tenant_id,
            Role.deleted_at.is_(None),
        )
        result = await db.execute(q)
        role = result.scalar_one_or_none()
        if role is None:
            return False

        role.deleted_at = datetime.now(UTC)
        await db.flush()
        return True

    def _role_to_dict(self, role: Role) -> dict[str, Any]:
        """Convert role to response dict."""
        return {
            "id": str(role.id),
            "name": role.name,
            "permissions": role.permissions,
            "denied_permissions": role.denied_permissions,
            "field_permissions": role.field_permissions,
            "permission_version": role.permission_version,
        }


role_service = RoleService()
