from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy import or_
from sqlalchemy.orm import Session

from app.api.deps import require_roles
from app.db.session import get_db
from app.models import AdminUser, Learner, LearnerNameHistory
from app.schemas.learner import LearnerCreate, LearnerOut, LearnerUpdate
from app.services.logs import diff_values, log_action, mask_phone

router = APIRouter()


@router.get("", response_model=list[LearnerOut])
def list_learners(
    keyword: str | None = Query(default=None),
    db: Session = Depends(get_db),
    _: AdminUser = Depends(require_roles("system_admin", "certificate_admin", "readonly")),
) -> list[Learner]:
    query = db.query(Learner).filter(Learner.status != "deleted").order_by(Learner.id.desc())
    if keyword:
        like = f"%{keyword}%"
        query = query.filter(or_(Learner.current_name.like(like), Learner.phone.like(like), Learner.student_no.like(like)))
    return query.limit(100).all()


@router.post("", response_model=LearnerOut, status_code=status.HTTP_201_CREATED)
def create_learner(
    payload: LearnerCreate,
    db: Session = Depends(get_db),
    admin: AdminUser = Depends(require_roles("system_admin", "certificate_admin")),
) -> Learner:
    existing = db.query(Learner).filter(Learner.phone == payload.phone).first()
    if existing:
        if existing.current_name != payload.current_name:
            db.add(LearnerNameHistory(learner_id=existing.id, name=payload.current_name, source="manual"))
        existing.current_name = payload.current_name
        existing.student_no = payload.student_no
        existing.remark = payload.remark
        log_action(db, admin, "update_learner", "learner", existing.id, {"name": existing.current_name, "phone": mask_phone(existing.phone)})
        db.commit()
        db.refresh(existing)
        return existing
    learner = Learner(
        phone=payload.phone,
        current_name=payload.current_name,
        student_no=payload.student_no,
        remark=payload.remark,
    )
    db.add(learner)
    db.commit()
    db.refresh(learner)
    db.add(LearnerNameHistory(learner_id=learner.id, name=learner.current_name, source="manual"))
    log_action(db, admin, "create_learner", "learner", learner.id, {"name": learner.current_name, "phone": mask_phone(learner.phone), "status": learner.status})
    db.commit()
    return learner


@router.get("/{learner_id}", response_model=LearnerOut)
def get_learner(
    learner_id: int,
    db: Session = Depends(get_db),
    _: AdminUser = Depends(require_roles("system_admin", "certificate_admin", "readonly")),
) -> Learner:
    learner = db.get(Learner, learner_id)
    if not learner:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Learner not found")
    return learner


@router.put("/{learner_id}", response_model=LearnerOut)
def update_learner(
    learner_id: int,
    payload: LearnerUpdate,
    db: Session = Depends(get_db),
    admin: AdminUser = Depends(require_roles("system_admin", "certificate_admin")),
) -> Learner:
    learner = db.get(Learner, learner_id)
    if not learner:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Learner not found")
    duplicate = db.query(Learner).filter(Learner.phone == payload.phone, Learner.id != learner_id).first()
    if duplicate:
        raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Phone already exists")
    before = {
        "phone": learner.phone,
        "current_name": learner.current_name,
        "student_no": learner.student_no,
        "status": learner.status,
        "remark": learner.remark,
    }
    if learner.current_name != payload.current_name:
        db.add(LearnerNameHistory(learner_id=learner.id, name=payload.current_name, source="manual"))
    learner.phone = payload.phone
    learner.current_name = payload.current_name
    learner.student_no = payload.student_no
    learner.status = payload.status
    learner.remark = payload.remark
    after = {
        "phone": learner.phone,
        "current_name": learner.current_name,
        "student_no": learner.student_no,
        "status": learner.status,
        "remark": learner.remark,
    }
    changes = diff_values(before, after, list(after.keys()))
    if "phone" in changes:
        changes["phone"] = {"before": mask_phone(changes["phone"]["before"]), "after": mask_phone(changes["phone"]["after"])}
    log_action(db, admin, "update_learner", "learner", learner.id, {"name": learner.current_name, "phone": mask_phone(learner.phone), "changes": changes})
    db.commit()
    db.refresh(learner)
    return learner


@router.delete("/{learner_id}")
def delete_learner(
    learner_id: int,
    db: Session = Depends(get_db),
    admin: AdminUser = Depends(require_roles("system_admin", "certificate_admin")),
) -> dict[str, bool]:
    learner = db.get(Learner, learner_id)
    if not learner:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Learner not found")
    learner.status = "deleted"
    log_action(db, admin, "delete_learner", "learner", learner.id, {"name": learner.current_name, "phone": mask_phone(learner.phone)})
    db.commit()
    return {"ok": True}
