"""Group management service."""

from __future__ import annotations

import uuid
from typing import Any

from sqlalchemy import delete, func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.permissions import invalidate_all_user_permissions
from app.models.group import Group, UserGroup
from app.models.user import User, UserTenant


class GroupService:
    """Handles group CRUD and user-group membership."""

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

    async def get_group(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        group_id: uuid.UUID,
    ) -> Group | None:
        """Get a single group by ID within tenant scope."""
        q = select(Group).where(
            Group.id == group_id,
            Group.tenant_id == tenant_id,
            Group.deleted_at.is_(None),
        )
        result = await db.execute(q)
        return result.scalar_one_or_none()

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

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

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

        if version_bump:
            group.permission_version += 1

        await db.flush()
        return group

    async def delete_group(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        group_id: uuid.UUID,
    ) -> bool:
        """Soft-delete a group."""
        from datetime import UTC, datetime

        q = select(Group).where(
            Group.id == group_id,
            Group.tenant_id == tenant_id,
            Group.deleted_at.is_(None),
        )
        result = await db.execute(q)
        group = result.scalar_one_or_none()
        if group is None:
            return False

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

    async def get_group_members(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        group_id: uuid.UUID,
    ) -> list[dict[str, Any]]:
        """List all users in a group."""
        q = (
            select(User, UserGroup)
            .join(User, UserGroup.user_id == User.id)
            .where(
                UserGroup.group_id == group_id,
                UserGroup.tenant_id == tenant_id,
            )
        )
        result = await db.execute(q)
        return [
            {
                "user_id": str(user.id),
                "email": user.email,
                "name": user.name,
                "is_active": user.is_active,
            }
            for user, _ug in result.all()
        ]

    async def add_user_to_group(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        group_id: uuid.UUID,
        user_id: uuid.UUID,
    ) -> bool:
        """Add a user to a group."""
        # Verify user is in this tenant
        ut_q = select(UserTenant).where(
            UserTenant.user_id == user_id,
            UserTenant.tenant_id == tenant_id,
        )
        ut_result = await db.execute(ut_q)
        if ut_result.scalar_one_or_none() is None:
            return False

        # Check if already member
        existing_q = select(UserGroup).where(
            UserGroup.user_id == user_id,
            UserGroup.group_id == group_id,
            UserGroup.tenant_id == tenant_id,
        )
        existing_result = await db.execute(existing_q)
        if existing_result.scalar_one_or_none() is not None:
            return True  # Already member

        ug = UserGroup(
            user_id=user_id,
            group_id=group_id,
            tenant_id=tenant_id,
        )
        db.add(ug)
        await db.flush()
        return True

    async def remove_user_from_group(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        group_id: uuid.UUID,
        user_id: uuid.UUID,
    ) -> bool:
        """Remove a user from a group."""
        q = delete(UserGroup).where(
            UserGroup.user_id == user_id,
            UserGroup.group_id == group_id,
            UserGroup.tenant_id == tenant_id,
        )
        result = await db.execute(q)
        await db.flush()
        return result.rowcount > 0

    async def get_user_groups(
        self,
        db: AsyncSession,
        tenant_id: uuid.UUID,
        user_id: uuid.UUID,
    ) -> list[dict[str, Any]]:
        """List all groups a user is member of."""
        q = (
            select(Group)
            .join(UserGroup, UserGroup.group_id == Group.id)
            .where(
                UserGroup.user_id == user_id,
                UserGroup.tenant_id == tenant_id,
                Group.deleted_at.is_(None),
            )
        )
        result = await db.execute(q)
        return [self._group_to_dict(g) for g in result.scalars().all()]

    def _group_to_dict(self, group: Group) -> dict[str, Any]:
        """Convert group to response dict."""
        return {
            "id": str(group.id),
            "name": group.name,
            "description": group.description,
            "permissions": group.permissions,
            "denied_permissions": group.denied_permissions,
            "field_permissions": group.field_permissions,
            "permission_version": group.permission_version,
        }


group_service = GroupService()
