"""Group management routes."""

from __future__ import annotations

import uuid

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.audit import log_audit
from app.core.auth import get_redis
from app.core.db import get_db
from app.core.permissions import invalidate_all_user_permissions
from app.deps import get_current_user, require_permission
from app.schemas.group import AddMemberRequest, GroupCreate, GroupUpdate
from app.services.group_service import group_service

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


@router.get("")
async def list_groups(
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("groups:read")),
):
    """List all groups in the current tenant."""
    import uuid as _uuid

    tenant_id = _uuid.UUID(current_user["tenant_id"])
    return {"items": await group_service.list_groups(db, tenant_id)}


@router.post("", status_code=status.HTTP_201_CREATED)
async def create_group(
    body: GroupCreate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("groups:write")),
):
    """Create a new group."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    acting_user_id = uuid.UUID(current_user["user_id"])

    group = await group_service.create_group(
        db,
        tenant_id,
        body.name,
        body.description,
        body.permissions,
        body.denied_permissions,
        body.field_permissions,
    )

    await log_audit(
        db, tenant_id, acting_user_id, "create", "group", group.id,
        changes={"name": body.name},
    )

    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,
    }


@router.get("/{group_id}")
async def get_group(
    group_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """Get a single group."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    try:
        gid = uuid.UUID(group_id)
    except ValueError:
        raise HTTPException(400, detail={"detail": "Invalid group_id", "code": "invalid_id"}) from None

    group = await group_service.get_group(db, tenant_id, gid)
    if group is None:
        raise HTTPException(404, detail={"detail": "Group not found", "code": "not_found"})

    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,
    }


@router.patch("/{group_id}")
async def update_group(
    group_id: str,
    body: GroupUpdate,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("groups:write")),
):
    """Update a group."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    acting_user_id = uuid.UUID(current_user["user_id"])
    try:
        gid = uuid.UUID(group_id)
    except ValueError:
        raise HTTPException(400, detail={"detail": "Invalid group_id", "code": "invalid_id"}) from None

    group = await group_service.update_group(
        db, tenant_id, gid,
        body.name, body.description,
        body.permissions, body.denied_permissions, body.field_permissions,
    )
    if group is None:
        raise HTTPException(404, detail={"detail": "Group not found", "code": "not_found"})

    # Invalidate permission cache for all users in this tenant
    redis = get_redis()
    await invalidate_all_user_permissions(redis, tenant_id)

    await log_audit(
        db, tenant_id, acting_user_id, "update", "group", gid,
        changes=body.model_dump(exclude_none=True),
    )

    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,
    }


@router.delete("/{group_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_group(
    group_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("groups:delete")),
):
    """Delete a group."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    acting_user_id = uuid.UUID(current_user["user_id"])
    try:
        gid = uuid.UUID(group_id)
    except ValueError:
        raise HTTPException(400, detail={"detail": "Invalid group_id", "code": "invalid_id"}) from None

    success = await group_service.delete_group(db, tenant_id, gid)
    if not success:
        raise HTTPException(404, detail={"detail": "Group not found", "code": "not_found"})

    # Invalidate permission cache
    redis = get_redis()
    await invalidate_all_user_permissions(redis, tenant_id)

    await log_audit(
        db, tenant_id, acting_user_id, "delete", "group", gid,
    )


@router.get("/{group_id}/members")
async def list_group_members(
    group_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """List all members of a group."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    try:
        gid = uuid.UUID(group_id)
    except ValueError:
        raise HTTPException(400, detail={"detail": "Invalid group_id", "code": "invalid_id"}) from None

    members = await group_service.get_group_members(db, tenant_id, gid)
    return {"items": members}


@router.post("/{group_id}/members")
async def add_group_member(
    group_id: str,
    body: AddMemberRequest,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("groups:write")),
):
    """Add a user to a group."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    acting_user_id = uuid.UUID(current_user["user_id"])
    try:
        gid = uuid.UUID(group_id)
        uid = uuid.UUID(body.user_id)
    except ValueError:
        raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"}) from None

    success = await group_service.add_user_to_group(db, tenant_id, gid, uid)
    if not success:
        raise HTTPException(404, detail={"detail": "Group or user not found in tenant", "code": "not_found"})

    # Invalidate permission cache for this user
    redis = get_redis()
    from app.core.permissions import invalidate_permission_cache
    await invalidate_permission_cache(redis, uid, tenant_id)

    await log_audit(
        db, tenant_id, acting_user_id, "add_member", "group", gid,
        changes={"user_id": body.user_id},
    )

    return {"message": "User added to group"}


@router.delete("/{group_id}/members/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def remove_group_member(
    group_id: str,
    user_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(require_permission("groups:write")),
):
    """Remove a user from a group."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    acting_user_id = uuid.UUID(current_user["user_id"])
    try:
        gid = uuid.UUID(group_id)
        uid = uuid.UUID(user_id)
    except ValueError:
        raise HTTPException(400, detail={"detail": "Invalid ID", "code": "invalid_id"}) from None

    success = await group_service.remove_user_from_group(db, tenant_id, gid, uid)
    if not success:
        raise HTTPException(404, detail={"detail": "Membership not found", "code": "not_found"})

    # Invalidate permission cache for this user
    redis = get_redis()
    from app.core.permissions import invalidate_permission_cache
    await invalidate_permission_cache(redis, uid, tenant_id)

    await log_audit(
        db, tenant_id, acting_user_id, "remove_member", "group", gid,
        changes={"user_id": user_id},
    )


@router.get("/user/{user_id}")
async def get_user_groups(
    user_id: str,
    db: AsyncSession = Depends(get_db),
    current_user: dict = Depends(get_current_user),
):
    """List all groups a user is member of."""
    tenant_id = uuid.UUID(current_user["tenant_id"])
    try:
        uid = uuid.UUID(user_id)
    except ValueError:
        raise HTTPException(400, detail={"detail": "Invalid user_id", "code": "invalid_id"}) from None

    groups = await group_service.get_user_groups(db, tenant_id, uid)
    return {"items": groups}
