from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.core.db import get_db
from app.core.deps import require_roles
from app.core.security import hash_password
from app.models.models import User
from app.schemas.user import UserCreate, UserOut, UserUpdate
from app.services.audit import write_audit_log

router = APIRouter()


@router.get("", response_model=list[UserOut])
async def list_users(admin: User = Depends(require_roles("admin")), db: AsyncSession = Depends(get_db)) -> list[UserOut]:
    users = (await db.scalars(select(User).order_by(User.id.asc()))).all()
    _ = admin
    return [UserOut.model_validate(user) for user in users]


@router.post("", response_model=UserOut, status_code=status.HTTP_201_CREATED)
async def create_user(payload: UserCreate, admin: User = Depends(require_roles("admin")), db: AsyncSession = Depends(get_db)) -> UserOut:
    exists = await db.scalar(select(User).where(User.email == payload.email))
    if exists:
        raise HTTPException(status_code=409, detail="Email already exists")
    user = User(
        email=payload.email,
        first_name=payload.first_name,
        last_name=payload.last_name,
        password_hash=hash_password(payload.password),
        role=payload.role,
    )
    db.add(user)
    await db.commit()
    await db.refresh(user)
    await write_audit_log(db, "admin.user.create", admin.id, {"created_user_id": user.id})
    return UserOut.model_validate(user)


@router.put("/{user_id}", response_model=UserOut)
async def update_user(
    user_id: int,
    payload: UserUpdate,
    admin: User = Depends(require_roles("admin")),
    db: AsyncSession = Depends(get_db),
) -> UserOut:
    user = await db.scalar(select(User).where(User.id == user_id))
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    update_data = payload.model_dump(exclude_unset=True)
    next_email = update_data.get("email")
    if next_email and next_email != user.email:
        existing = await db.scalar(select(User).where(User.email == next_email))
        if existing and existing.id != user.id:
            raise HTTPException(status_code=409, detail="Email already exists")
    if "password" in update_data:
        raw_password = update_data.pop("password")
        if raw_password:
            user.password_hash = hash_password(raw_password)
    for key, value in update_data.items():
        setattr(user, key, value)
    await db.commit()
    await db.refresh(user)
    await write_audit_log(db, "admin.user.update", admin.id, {"updated_user_id": user.id})
    return UserOut.model_validate(user)


@router.delete("/{user_id}")
async def delete_user(user_id: int, admin: User = Depends(require_roles("admin")), db: AsyncSession = Depends(get_db)) -> dict:
    if user_id == admin.id:
        raise HTTPException(status_code=400, detail="Cannot delete yourself")
    user = await db.scalar(select(User).where(User.id == user_id))
    if not user:
        raise HTTPException(status_code=404, detail="User not found")
    await db.delete(user)
    await db.commit()
    await write_audit_log(db, "admin.user.delete", admin.id, {"deleted_user_id": user_id})
    return {"status": "deleted"}
