"""/admin-api/users 接口：仅供 X-Admin-Api-Key 调用。

- 读取（list/get/search）
- 常规写入（创建用户、更新非敏感字段）
- **绝不**包含：修改 mobile/role/status、删除用户、提升超管、批量操作

任何敏感字段一经传入，直接 422（pydantic extra=forbid）或 400 拒绝。
"""
import logging
from typing import List, Optional

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

from app.api.v1 import deps
from app.core import security
from app.core.utils import generate_english_name, get_client_ip
from app.models.admin_api_key import AdminApiKey
from app.models.organization import Organization
from app.models.user import User, UserRole
from app.schemas.admin_api_key import AdminApiUserCreate, AdminApiUserUpdate
from app.schemas.operation_log import ActionType
from app.schemas.user import User as UserSchema, UserList
from app.services.log_service import LogService

router = APIRouter()
logger = logging.getLogger(__name__)


def _audit_details(api_key: AdminApiKey, extra: Optional[dict] = None) -> dict:
    base = {
        "via": "admin_api_key",
        "key_id": api_key.id,
        "key_prefix": api_key.key_prefix,
    }
    if extra:
        base.update(extra)
    return base


def _ensure_unique_name(db: Session, base_name: str, exclude_user_id: Optional[int] = None) -> str:
    name = base_name
    counter = 1
    while True:
        q = db.query(User).filter(User.name == name, User.is_deleted == 0)
        if exclude_user_id is not None:
            q = q.filter(User.id != exclude_user_id)
        if not q.first():
            return name
        name = f"{base_name}{counter}"
        counter += 1


def _ensure_unique_english_name(
    db: Session, base_name: str, exclude_user_id: Optional[int] = None
) -> str:
    name = base_name
    counter = 1
    while True:
        q = db.query(User).filter(User.english_name == name, User.is_deleted == 0)
        if exclude_user_id is not None:
            q = q.filter(User.id != exclude_user_id)
        if not q.first():
            return name
        name = f"{base_name}{counter}"
        counter += 1


@router.get("/", response_model=UserList, summary="用户列表（管理 API）")
def list_users(
    skip: int = 0,
    limit: int = 50,
    status_param: Optional[str] = Query(None, alias="status"),
    role: Optional[str] = None,
    mobile: Optional[str] = None,
    name: Optional[str] = None,
    english_name: Optional[str] = None,
    keyword: Optional[str] = None,
    organization_id: Optional[int] = None,
    db: Session = Depends(deps.get_db),
    api_key: AdminApiKey = Depends(deps.get_admin_api_key),
):
    if "user:read" not in (api_key.scopes or "").split(","):
        raise HTTPException(status_code=403, detail="API Key 缺少 user:read 权限")

    query = db.query(User).filter(User.is_deleted == 0)

    if organization_id is not None:
        if organization_id == 0:
            query = query.filter(User.organization_id.is_(None))
        else:
            query = query.filter(User.organization_id == organization_id)

    if status_param:
        query = query.filter(User.status == status_param)
    if role:
        query = query.filter(User.role == role)
    if mobile:
        query = query.filter(User.mobile.ilike(f"%{mobile}%"))
    if name:
        query = query.filter(User.name.ilike(f"%{name}%"))
    if english_name:
        query = query.filter(User.english_name.ilike(f"%{english_name}%"))
    if keyword:
        query = query.filter(
            or_(
                User.mobile.ilike(f"%{keyword}%"),
                User.name.ilike(f"%{keyword}%"),
                User.english_name.ilike(f"%{keyword}%"),
            )
        )

    total = query.count()
    users = (
        query.options(joinedload(User.organization))
        .order_by(User.id.desc())
        .offset(skip)
        .limit(limit)
        .all()
    )
    return {"total": total, "items": users}


@router.get("/search", response_model=List[UserSchema], summary="搜索用户（管理 API）")
def search_users(
    keyword: Optional[str] = Query(None, alias="q"),
    limit: int = 20,
    db: Session = Depends(deps.get_db),
    api_key: AdminApiKey = Depends(deps.get_admin_api_key),
):
    if "user:read" not in (api_key.scopes or "").split(","):
        raise HTTPException(status_code=403, detail="API Key 缺少 user:read 权限")

    query = (
        db.query(User)
        .options(joinedload(User.organization))
        .filter(User.is_deleted == 0, User.status == "ACTIVE")
    )
    if keyword:
        query = query.filter(
            or_(
                User.mobile.ilike(f"%{keyword}%"),
                User.name.ilike(f"%{keyword}%"),
                User.english_name.ilike(f"%{keyword}%"),
            )
        )
    return query.limit(limit).all()


@router.get("/{user_id}", response_model=UserSchema, summary="用户详情（管理 API）")
def get_user(
    user_id: int,
    db: Session = Depends(deps.get_db),
    api_key: AdminApiKey = Depends(deps.get_admin_api_key),
):
    if "user:read" not in (api_key.scopes or "").split(","):
        raise HTTPException(status_code=403, detail="API Key 缺少 user:read 权限")

    user = (
        db.query(User)
        .options(joinedload(User.organization))
        .filter(User.id == user_id, User.is_deleted == 0)
        .first()
    )
    if not user:
        raise HTTPException(status_code=404, detail="用户不存在")
    return user


@router.post("/", response_model=UserSchema, summary="创建用户（管理 API）")
def create_user(
    body: AdminApiUserCreate,
    request: Request,
    db: Session = Depends(deps.get_db),
    api_key: AdminApiKey = Depends(deps.get_admin_api_key),
):
    """创建普通用户。强制 role=ORDINARY_USER, status=ACTIVE。"""
    if "user:write" not in (api_key.scopes or "").split(","):
        raise HTTPException(status_code=403, detail="API Key 缺少 user:write 权限")

    if db.query(User).filter(User.mobile == body.mobile).first():
        raise HTTPException(status_code=400, detail="该手机号已在系统中注册")

    password = (body.password or "").strip()
    if not password:
        raise HTTPException(status_code=400, detail="密码不能为空")

    raw_name = (body.name or "").replace(" ", "")
    if not raw_name:
        random_suffix = security.generate_alphanumeric_password(6)
        raw_name = f"用户{random_suffix}"
    final_name = _ensure_unique_name(db, raw_name)

    raw_english = body.english_name or generate_english_name(final_name) or ""
    final_english = _ensure_unique_english_name(db, raw_english) if raw_english else None

    org_id = None
    if body.organization_id is not None:
        org = db.query(Organization).filter(Organization.id == body.organization_id).first()
        if not org:
            raise HTTPException(status_code=400, detail="组织不存在")
        org_id = body.organization_id

    db_user = User(
        mobile=body.mobile,
        name=final_name,
        english_name=final_english,
        password_hash=security.get_password_hash(password),
        status="ACTIVE",
        role=UserRole.ORDINARY_USER,
        organization_id=org_id,
    )
    db.add(db_user)
    db.commit()
    db_user = (
        db.query(User)
        .options(joinedload(User.organization))
        .filter(User.id == db_user.id)
        .first()
    )

    LogService.create_log(
        db=db,
        operator_id=api_key.created_by,
        action_type=ActionType.MANUAL_ADD,
        target_user_id=db_user.id,
        target_mobile=db_user.mobile,
        ip_address=get_client_ip(request),
        details=_audit_details(api_key, {"role": db_user.role}),
    )
    logger.info(
        f"[admin-api] 创建用户: {db_user.mobile} (key_prefix={api_key.key_prefix})"
    )
    return db_user


@router.put("/{user_id}", response_model=UserSchema, summary="更新用户（管理 API，白名单字段）")
def update_user(
    user_id: int,
    body: AdminApiUserUpdate,
    request: Request,
    db: Session = Depends(deps.get_db),
    api_key: AdminApiKey = Depends(deps.get_admin_api_key),
):
    """仅允许更新 name / english_name / password / organization_id。

    传入 mobile / role / status / is_deleted 由 pydantic extra=forbid 直接 422。
    """
    if "user:write" not in (api_key.scopes or "").split(","):
        raise HTTPException(status_code=403, detail="API Key 缺少 user:write 权限")

    user = db.query(User).filter(User.id == user_id, User.is_deleted == 0).first()
    if not user:
        raise HTTPException(status_code=404, detail="用户不存在")

    update_data = body.model_dump(exclude_unset=True)
    if not update_data:
        raise HTTPException(status_code=400, detail="未提供需更新的字段")

    changes: dict = {}

    if "name" in update_data:
        new_name = (update_data["name"] or "").replace(" ", "")
        if not new_name:
            raise HTTPException(status_code=400, detail="姓名不能为空")
        new_name = _ensure_unique_name(db, new_name, exclude_user_id=user.id)
        if new_name != user.name:
            changes["name"] = {"old": user.name, "new": new_name}
            user.name = new_name
            # name 变更后，如果未显式传 english_name，则自动重生成
            if "english_name" not in update_data:
                generated = generate_english_name(new_name)
                if generated:
                    final_english = _ensure_unique_english_name(
                        db, generated, exclude_user_id=user.id
                    )
                    if final_english != user.english_name:
                        changes["english_name"] = {
                            "old": user.english_name,
                            "new": final_english,
                            "auto": True,
                        }
                        user.english_name = final_english

    if "english_name" in update_data:
        new_eng = update_data["english_name"]
        if new_eng:
            new_eng = _ensure_unique_english_name(db, new_eng, exclude_user_id=user.id)
        if new_eng != user.english_name:
            changes["english_name"] = {"old": user.english_name, "new": new_eng}
            user.english_name = new_eng

    if "organization_id" in update_data:
        new_org_id = update_data["organization_id"]
        if new_org_id is not None:
            if not db.query(Organization).filter(Organization.id == new_org_id).first():
                raise HTTPException(status_code=400, detail="组织不存在")
        if new_org_id != user.organization_id:
            changes["organization_id"] = {"old": user.organization_id, "new": new_org_id}
            user.organization_id = new_org_id

    if "password" in update_data:
        new_password = (update_data["password"] or "").strip()
        if not new_password:
            raise HTTPException(status_code=400, detail="新密码不能为空")
        user.password_hash = security.get_password_hash(new_password)
        changes["password"] = {"changed": True}

    if not changes:
        raise HTTPException(status_code=400, detail="未检测到变更")

    db.add(user)
    db.commit()
    user = (
        db.query(User)
        .options(joinedload(User.organization))
        .filter(User.id == user.id)
        .first()
    )

    LogService.create_log(
        db=db,
        operator_id=api_key.created_by,
        action_type=ActionType.UPDATE,
        target_user_id=user.id,
        target_mobile=user.mobile,
        ip_address=get_client_ip(request),
        details=_audit_details(api_key, {"changes": changes}),
    )
    logger.info(
        f"[admin-api] 更新用户: {user.mobile} (key_prefix={api_key.key_prefix}, changes={list(changes.keys())})"
    )
    return user
