from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import JSONResponse
from pydantic import BaseModel
from typing import List

from model.access_token_model import AccessTokenModel
from model.staff_model import StaffModel
from utils.auth_helper import assert_actor_match, get_current_actor_required, requires_permission
from utils.settings import ACCESS_TOKEN_TTL_HOURS
from utils.turnstile_helper import verify_turnstile

router = APIRouter()

STAFF_MANAGEMENT_PERMISSION = "staff_management"


def _client_ip(request: Request) -> str:
    return request.client.host if request.client else ""


class AddStaffRequest(BaseModel):
    name: str
    email: str
    permissions: List[str] = []
    actorId: str


@router.post("/add-staff", status_code=status.HTTP_201_CREATED, dependencies=[Depends(verify_turnstile)])
async def add_staff_controller(
    req: AddStaffRequest,
    current_user=Depends(requires_permission(STAFF_MANAGEMENT_PERMISSION)),
):
    if not req.name or not req.email:
        raise HTTPException(status_code=400, detail="Tên và Email là bắt buộc")

    try:
        actor_id = current_user["id"]
        actor_name = current_user.get("name", "")
        assert_actor_match(current_user, req.actorId)

        new_staff_data = StaffModel.create_staff(
            name=req.name.strip(),
            email=req.email.strip(),
            permissions=req.permissions,
        )

        return {
            "success": True,
            "data": new_staff_data,
            "actedBy": {
                "id": actor_id,
                "name": actor_name,
            },
        }

    except Exception as e:
        print(f"Lỗi khi tạo staff: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@router.get("/add-staff", dependencies=[Depends(requires_permission(STAFF_MANAGEMENT_PERMISSION))])
async def get_staff_list():
    try:
        from model.staff_model import collection

        staffs = list(collection.find({"role": "staff"}))

        for s in staffs:
            s["_id"] = str(s["_id"])
            # Không trả hash password/plain password ra frontend.
            s.pop("password", None)

        return {"success": True, "data": staffs}
    except Exception as e:
        return {"success": False, "message": str(e)}


class StaffLoginPayload(BaseModel):
    email: str
    password: str


@router.post("/auth/login", dependencies=[Depends(verify_turnstile)])
async def staff_login(payload: StaffLoginPayload, request: Request):
    from model.staff_model import collection
    from utils.password_helper import hash_password, is_password_hash, verify_password

    user = collection.find_one({"email": payload.email, "role": "staff"})

    if user and verify_password(payload.password, user.get("password", "")):
        if user.get("status") == "inactive":
            return {"success": False, "message": "Tài khoản của bạn đã bị khóa!"}

        # Tự động nâng cấp password plaintext cũ sang hash sau khi login đúng.
        if not is_password_hash(user.get("password", "")):
            collection.update_one(
                {"_id": user["_id"]},
                {"$set": {"password": hash_password(payload.password)}},
            )

        issued = AccessTokenModel.issue_token(
            actor_id=str(user["_id"]),
            actor_role="staff",
            ttl_hours=ACCESS_TOKEN_TTL_HOURS,
            created_by_ip=_client_ip(request),
            user_agent=request.headers.get("user-agent", ""),
        )

        return {
            "success": True,
            "data": {
                "accessToken": issued["rawToken"],
                "tokenType": "Bearer",
                "expiresIn": ACCESS_TOKEN_TTL_HOURS * 3600,
                "user": {
                    "id": str(user["_id"]),
                    "email": user["email"],
                    "name": user.get("name", ""),
                    "role": user["role"],
                    "permissions": user.get("permissions", []),
                    "status": user.get("status", "active"),
                },
            },
        }

    return {"success": False, "message": "Email hoặc mật khẩu Staff không chính xác!"}


class ChangePasswordPayload(BaseModel):
    oldPassword: str
    newPassword: str


@router.put("/change-password", dependencies=[Depends(verify_turnstile)])
async def change_staff_password(
    payload: ChangePasswordPayload,
    current_user=Depends(get_current_actor_required),
):
    if current_user.get("role") != "staff":
        raise HTTPException(status_code=403, detail="Staff account required")

    success, message = StaffModel.change_password(
        staff_id=current_user["id"],
        old_password=payload.oldPassword,
        new_password=payload.newPassword,
    )

    return {"success": success, "message": message}


class UpdateStaffPayload(BaseModel):
    staffId: str
    email: str
    status: str
    permissions: List[str]
    actorId: str


class ForgotPasswordPayload(BaseModel):
    email: str


@router.post("/forgot-password", dependencies=[Depends(verify_turnstile)])
async def forgot_password(payload: ForgotPasswordPayload):
    try:
        StaffModel.forgot_password_by_email(payload.email.strip().lower())
        return {"success": True, "message": "Mật khẩu mới đã được gửi về email của bạn."}
    except ValueError as e:
        return JSONResponse(status_code=400, content={"success": False, "message": str(e)})
    except Exception:
        return JSONResponse(status_code=500, content={"success": False, "message": "Lỗi server, vui lòng thử lại."})


class ResetPasswordPayload(BaseModel):
    staffId: str
    actorId: str


@router.put("/update-staff", dependencies=[Depends(verify_turnstile)])
async def update_staff_endpoint(
    payload: UpdateStaffPayload,
    current_user=Depends(requires_permission(STAFF_MANAGEMENT_PERMISSION)),
):
    actor_id = current_user["id"]
    actor_name = current_user.get("name", "")
    assert_actor_match(current_user, payload.actorId)

    success, msg = StaffModel.update_staff(
        payload.staffId,
        payload.email,
        payload.status,
        payload.permissions,
    )

    if success:
        # Permission/status đổi thì token cũ nên bị đá ra để áp dụng ngay.
        AccessTokenModel.revoke_all_for_actor(payload.staffId)

    return {
        "success": success,
        "message": msg,
        "actedBy": {
            "id": actor_id,
            "name": actor_name,
        },
    }


@router.post("/reset-password", dependencies=[Depends(verify_turnstile)])
async def reset_password_endpoint(
    payload: ResetPasswordPayload,
    current_user=Depends(requires_permission(STAFF_MANAGEMENT_PERMISSION)),
):
    actor_id = current_user["id"]
    actor_name = current_user.get("name", "")
    assert_actor_match(current_user, payload.actorId)

    success, msg = StaffModel.admin_reset_password(payload.staffId)

    return {
        "success": success,
        "message": msg,
        "actedBy": {
            "id": actor_id,
            "name": actor_name,
        },
    }