"""Admin router for user management. Super Admin only."""
from typing import List, Optional
import uuid

from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import func
from sqlalchemy.ext.asyncio import AsyncSession
from sqlmodel import select, update

from models.sql.presentation import PresentationModel
from models.sql.user import UserModel
from services.database import get_async_session
from utils.auth_dependencies import require_super_admin

USERS_ROUTER = APIRouter(prefix="/users", tags=["Admin - Users"])

VALID_ROLES = {"super_admin", "client_admin", "user"}


class TransferOwnershipRequest(BaseModel):
    new_owner_id: uuid.UUID
    client_id: Optional[uuid.UUID] = None


@USERS_ROUTER.get("", response_model=List[dict])
async def list_users(
    _: UserModel = Depends(require_super_admin),
    is_active: Optional[bool] = Query(None),
    role: Optional[str] = Query(None),
    offset: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    session: AsyncSession = Depends(get_async_session),
):
    query = select(UserModel)
    if is_active is not None:
        query = query.where(UserModel.is_active == is_active)
    if role:
        query = query.where(UserModel.role == role)
    query = query.order_by(UserModel.created_at.desc()).offset(offset).limit(limit)

    result = await session.execute(query)
    users = result.scalars().all()
    return [
        {
            "id": str(u.id),
            "email": u.email,
            "display_name": u.display_name,
            "role": u.role,
            "is_active": u.is_active,
            "last_login_at": u.last_login_at.isoformat() if u.last_login_at else None,
            "created_at": u.created_at.isoformat() if u.created_at else None,
        }
        for u in users
    ]


@USERS_ROUTER.get("/{user_id}", response_model=dict)
async def get_user(
    user_id: uuid.UUID,
    _: UserModel = Depends(require_super_admin),
    session: AsyncSession = Depends(get_async_session),
):
    user = await session.get(UserModel, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    return {
        "id": str(user.id),
        "email": user.email,
        "display_name": user.display_name,
        "role": user.role,
        "is_active": user.is_active,
        "last_login_at": user.last_login_at.isoformat() if user.last_login_at else None,
        "created_at": user.created_at.isoformat() if user.created_at else None,
    }


@USERS_ROUTER.put("/{user_id}/role")
async def update_user_role(
    user_id: uuid.UUID,
    role: str = Query(...),
    admin: UserModel = Depends(require_super_admin),
    session: AsyncSession = Depends(get_async_session),
):
    if role not in VALID_ROLES:
        raise HTTPException(
            status_code=400,
            detail=f"Invalid role. Must be one of: {', '.join(VALID_ROLES)}",
        )

    user = await session.get(UserModel, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    if user.id == admin.id:
        raise HTTPException(status_code=400, detail="Cannot change your own role")

    user.role = role
    session.add(user)
    await session.commit()
    return {"message": "Role updated", "user_id": str(user.id), "role": role}


@USERS_ROUTER.post("/{user_id}/transfer-ownership")
async def transfer_ownership(
    user_id: uuid.UUID,
    body: TransferOwnershipRequest,
    _: UserModel = Depends(require_super_admin),
    session: AsyncSession = Depends(get_async_session),
):
    """Transfer all presentations from one user to another.

    Used for GDPR compliance before deactivating a user.
    """
    if user_id == body.new_owner_id:
        raise HTTPException(
            status_code=400, detail="Cannot transfer ownership to the same user"
        )

    # Validate source user exists
    source_user = await session.get(UserModel, user_id)
    if not source_user:
        raise HTTPException(status_code=404, detail="Source user not found")

    # Validate target user exists
    target_user = await session.get(UserModel, body.new_owner_id)
    if not target_user:
        raise HTTPException(status_code=404, detail="Target user not found")

    # Build the update statement for non-deleted presentations owned by the source user
    stmt = (
        update(PresentationModel)
        .where(PresentationModel.owner_id == user_id)
        .where(PresentationModel.deleted_at.is_(None))
    )

    if body.client_id is not None:
        stmt = stmt.where(PresentationModel.client_id == body.client_id)

    stmt = stmt.values(owner_id=body.new_owner_id)
    result = await session.execute(stmt)
    await session.commit()

    transferred_count = result.rowcount

    return {
        "message": f"Transferred {transferred_count} presentations",
        "from_user_id": str(user_id),
        "to_user_id": str(body.new_owner_id),
    }


@USERS_ROUTER.delete("/{user_id}")
async def deactivate_user(
    user_id: uuid.UUID,
    admin: UserModel = Depends(require_super_admin),
    session: AsyncSession = Depends(get_async_session),
):
    user = await session.get(UserModel, user_id)
    if not user:
        raise HTTPException(status_code=404, detail="User not found")

    if user.id == admin.id:
        raise HTTPException(status_code=400, detail="Cannot deactivate yourself")

    # Check how many active presentations this user still owns
    count_query = (
        select(func.count())
        .select_from(PresentationModel)
        .where(PresentationModel.owner_id == user_id)
        .where(PresentationModel.deleted_at.is_(None))
    )
    count_result = await session.execute(count_query)
    presentation_count = count_result.scalar_one()

    user.is_active = False
    session.add(user)
    await session.commit()

    response = {"message": "User deactivated", "user_id": str(user.id)}

    if presentation_count > 0:
        response["warning"] = (
            f"User still has {presentation_count} active presentations. "
            "Consider transferring ownership first."
        )

    return response
