from typing import Annotated
from uuid import UUID

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

from app.auth.deps import CurrentUser, require_admin
from app.auth.security import hash_password
from app.db import get_session
from app.schemas.user import UserCreate, UserOut, UserUpdate

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


@router.get("", response_model=list[UserOut])
async def list_users(
    session: Annotated[AsyncSession, Depends(get_session)],
    _admin: Annotated[CurrentUser, Depends(require_admin)],
) -> list[UserOut]:
    rows = (
        await session.execute(
            text(
                "SELECT id::text, email, role, is_active, created_at FROM users ORDER BY created_at"
            )
        )
    ).all()
    return [
        UserOut(id=r[0], email=r[1], role=r[2], is_active=r[3], created_at=r[4]) for r in rows
    ]


@router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED)
async def create_user(
    payload: UserCreate,
    session: Annotated[AsyncSession, Depends(get_session)],
    _admin: Annotated[CurrentUser, Depends(require_admin)],
) -> UserOut:
    existing = (
        await session.execute(text("SELECT 1 FROM users WHERE email = :e"), {"e": payload.email})
    ).first()
    if existing:
        raise HTTPException(status.HTTP_409_CONFLICT, "email already exists")
    row = (
        await session.execute(
            text(
                """
                INSERT INTO users (email, hashed_password, role)
                VALUES (:e, :p, :r)
                RETURNING id::text, email, role, is_active, created_at
                """
            ),
            {"e": payload.email, "p": hash_password(payload.password), "r": payload.role},
        )
    ).first()
    await session.commit()
    return UserOut(id=row[0], email=row[1], role=row[2], is_active=row[3], created_at=row[4])


@router.patch("/{user_id}", response_model=UserOut)
async def update_user(
    user_id: UUID,
    payload: UserUpdate,
    session: Annotated[AsyncSession, Depends(get_session)],
    _admin: Annotated[CurrentUser, Depends(require_admin)],
) -> UserOut:
    sets: list[str] = []
    params: dict[str, object] = {"id": str(user_id)}
    if payload.password:
        sets.append("hashed_password = :p")
        params["p"] = hash_password(payload.password)
    if payload.role is not None:
        sets.append("role = :r")
        params["r"] = payload.role
    if payload.is_active is not None:
        sets.append("is_active = :a")
        params["a"] = payload.is_active
    if not sets:
        raise HTTPException(status.HTTP_400_BAD_REQUEST, "nothing to update")
    q = "UPDATE users SET " + ", ".join(sets) + " WHERE id = :id RETURNING id::text, email, role, is_active, created_at"
    row = (await session.execute(text(q), params)).first()
    if not row:
        raise HTTPException(status.HTTP_404_NOT_FOUND)
    await session.commit()
    return UserOut(id=row[0], email=row[1], role=row[2], is_active=row[3], created_at=row[4])


@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_user(
    user_id: UUID,
    session: Annotated[AsyncSession, Depends(get_session)],
    admin: Annotated[CurrentUser, Depends(require_admin)],
) -> None:
    if str(user_id) == admin.id:
        raise HTTPException(status.HTTP_400_BAD_REQUEST, "cannot delete yourself")
    await session.execute(text("DELETE FROM users WHERE id = :id"), {"id": str(user_id)})
    await session.commit()
