import uuid

from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlalchemy import or_, select
from sqlalchemy.orm import Session

from flyway.api.deps import current_actor, get_db, require_admin_actor
from flyway.api.lists import IdsIn, Page, like, page_params, paginate
from flyway.api.views import user_out
from flyway.auth.service import (
    admin_set_password, create_user, delete_users, set_admin, set_locked, update_profile,
)
from flyway.domain.actor import Actor
from flyway.domain.errors import BusinessError
from flyway.models import AppUser

router = APIRouter(prefix="/api/users", dependencies=[Depends(require_admin_actor)])


class UserIn(BaseModel):
    username: str
    password: str
    first_name: str = ""
    last_name: str = ""
    email: str = ""
    mobile: str = ""
    is_admin: bool = False


class UserUpdateIn(BaseModel):
    first_name: str = ""
    last_name: str = ""
    email: str = ""
    mobile: str = ""
    is_admin: bool = False


class PasswordIn(BaseModel):
    password: str


class LockIn(IdsIn):
    locked: bool


def _user(db: Session, user_id: uuid.UUID) -> AppUser:
    user = db.get(AppUser, user_id)
    if user is None:
        raise BusinessError("Record not found.")
    return user


@router.get("")
def list_users(keyword: str | None = None, page: Page = Depends(page_params), db: Session = Depends(get_db)):
    q = select(AppUser)
    if keyword:
        q = q.where(or_(like(AppUser.username, keyword), like(AppUser.first_name, keyword),
                        like(AppUser.last_name, keyword)))
    rows, total = paginate(db, q, page, {"username": AppUser.username, "created_at": AppUser.created_at,
                                         "last_login_at": AppUser.last_login_at, "last_activity_at": AppUser.last_activity_at}, "username")
    return {"items": [user_out(u) for u in rows], "total": total}


@router.post("")
def create(body: UserIn, db: Session = Depends(get_db)):
    user = create_user(db, body.username, body.password, first_name=body.first_name, last_name=body.last_name,
                       email=body.email, admin=body.is_admin)
    user.mobile = body.mobile
    db.commit()
    return user_out(user)


@router.get("/{user_id}")
def get_user(user_id: uuid.UUID, db: Session = Depends(get_db)):
    return user_out(_user(db, user_id))


@router.put("/{user_id}")
def update(user_id: uuid.UUID, body: UserUpdateIn, db: Session = Depends(get_db)):
    user = _user(db, user_id)
    update_profile(db, user, first_name=body.first_name, last_name=body.last_name, email=body.email,
                   mobile=body.mobile)
    set_admin(user, body.is_admin)
    db.commit()
    return user_out(user)


@router.post("/{user_id}/password", status_code=204)
def reset_password(user_id: uuid.UUID, body: PasswordIn, db: Session = Depends(get_db)):
    admin_set_password(db, _user(db, user_id), body.password)
    db.commit()


@router.post("/lock", status_code=204)
def lock(body: LockIn, db: Session = Depends(get_db)):
    set_locked(db, body.ids, body.locked)
    db.commit()


@router.post("/delete", status_code=204)
def remove(body: IdsIn, db: Session = Depends(get_db), actor: Actor = Depends(current_actor)):
    delete_users(db, actor, body.ids)
    db.commit()
