from typing import Optional
from uuid import UUID
from fastapi import APIRouter, Depends, Query
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.auth.schemas.responses import UserResponse
from src.apps.users.schemas.requests import InviteUserRequest, UpdateUserRequest, UpdateRoleRequest
from src.apps.users.services.user_service import UserService
from src.core.dependencies import require_roles
from src.core.constants import UserRole
from src.core.schemas.response import success, paginated
from src.database.session import get_db

router = APIRouter(prefix="/users", tags=["Users"])


def _serialize_user(user, current_user_id: UUID) -> dict:
    data = UserResponse.model_validate(user).model_dump()
    data["is_current_user"] = (user.id == current_user_id)
    if not data.get("name"):
        full = f"{user.first_name} {user.last_name}".strip()
        data["name"] = full or user.email
    return data


@router.get("", response_model=dict)
async def list_users(
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=100),
    search: str = Query(None),
    role_min: Optional[str] = Query(None, description="Minimum role level (e.g. staff)"),
    active: Optional[bool] = Query(None, description="Filter by active status"),
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    users, total = await service.list_users(
        current_user.tenant_id, skip, limit, search, current_user_id=current_user.id,
        role_min=role_min, active_only=active,
    )
    return paginated(
        items=[_serialize_user(u, current_user.id) for u in users],
        total=total,
        page=(skip // limit) + 1,
        page_size=limit,
    )


@router.post("/invite", response_model=dict, status_code=201)
async def invite_user(
    body: InviteUserRequest,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    user = await service.invite_user(current_user.tenant_id, body.model_dump())
    # Enqueue invitation email (background job)
    try:
        import arq
        from src.core.config import settings
        from arq.connections import RedisSettings
        redis = await arq.create_pool(RedisSettings.from_dsn(settings.REDIS_URL))
        await redis.enqueue_job(
            "send_invitation_email",
            str(user.id),
            str(current_user.tenant_id),
            str(current_user.id),
        )
        await redis.aclose()
    except Exception:
        pass  # Email is best-effort; do not fail the invite if Redis is down
    return success(
        data=_serialize_user(user, current_user.id),
        message="Invitation sent.",
    )


@router.patch("/{user_id}/role", response_model=dict)
async def update_user_role(
    user_id: UUID,
    body: UpdateRoleRequest,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    user = await service.update_role(user_id, current_user.tenant_id, body.role, current_user.id)
    return success(data=_serialize_user(user, current_user.id), message="Role updated.")


@router.post("/{user_id}/resend-invitation", response_model=dict)
async def resend_invitation(
    user_id: UUID,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    user = await service.resend_invitation(user_id, current_user.tenant_id)
    try:
        import arq
        from src.core.config import settings
        from arq.connections import RedisSettings
        redis = await arq.create_pool(RedisSettings.from_dsn(settings.REDIS_URL))
        await redis.enqueue_job(
            "send_invitation_email",
            str(user.id),
            str(current_user.tenant_id),
            str(current_user.id),
            resend=True,
        )
        await redis.aclose()
    except Exception:
        pass
    return success(message="Invitation resent.")


@router.delete("/{user_id}/invitation", status_code=204)
async def cancel_invitation(
    user_id: UUID,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    await service.cancel_invitation(user_id, current_user.tenant_id)


@router.delete("/{user_id}", status_code=204)
async def remove_user(
    user_id: UUID,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    await service.remove_user(user_id, current_user.tenant_id, current_user.id)


@router.get("/{user_id}", response_model=dict)
async def get_user(
    user_id: UUID,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR, UserRole.MANAGER)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    user = await service.get_by_id(user_id, current_user.tenant_id)
    if not user:
        from src.core.exceptions import NotFoundError
        raise NotFoundError("User not found")
    return success(data=_serialize_user(user, current_user.id))


@router.patch("/{user_id}", response_model=dict)
async def update_user(
    user_id: UUID,
    body: UpdateUserRequest,
    current_user=Depends(require_roles(UserRole.ADMINISTRATOR)),
    db: AsyncSession = Depends(get_db),
):
    service = UserService(db)
    user = await service.update_user(user_id, current_user.tenant_id, body.model_dump(exclude_none=True))
    return success(data=_serialize_user(user, current_user.id), message="User updated.")
