"""管理员级 API Key 后台管理接口（仅超级管理员）。

注意：该模块只负责管理 Key 自身（创建/列表/编辑/禁用/启用/吊销），
**不暴露物理删除**。Key 调用业务接口的入口在 admin_api_users.py /
admin_api_orgs.py 中实现。
"""
import logging
import secrets
from typing import Optional

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

from app.api.v1 import deps
from app.core import security
from app.core.utils import get_client_ip
from app.models.admin_api_key import AdminApiKey
from app.models.user import User
from app.schemas.admin_api_key import (
    AdminApiKeyCreate,
    AdminApiKeyList,
    AdminApiKeyResponse,
    AdminApiKeyRevoke,
    AdminApiKeySecretDisplay,
    AdminApiKeyUpdate,
)
from app.schemas.operation_log import ActionType
from app.services.log_service import LogService
from app.services.sms_service import SmsService

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


KEY_PLAINTEXT_PREFIX = "ak_live_"  # 便于识别这是一把"管理员级永久 Key"
KEY_PREFIX_LEN = 12  # 保存到 DB 的前缀长度（含上面的固定前缀），与 deps 里 raw_key[:12] 对齐


def _ensure_super_admin(current_user: User) -> None:
    if current_user.role != "SUPER_ADMIN":
        raise HTTPException(status_code=403, detail="权限不足")


def _generate_plain_key() -> str:
    # 例如 ak_live_3F9A4c8e9b...（前缀 + 32 字节随机）
    return f"{KEY_PLAINTEXT_PREFIX}{secrets.token_urlsafe(32)}"


def _serialize(db: Session, key: AdminApiKey) -> AdminApiKey:
    """显式带上 creator 关系，避免 ORM 懒加载产生噪音。"""
    return (
        db.query(AdminApiKey)
        .options(joinedload(AdminApiKey.creator))
        .filter(AdminApiKey.id == key.id)
        .first()
    )


@router.post("/send-verification-code", summary="发送 API Key 操作短信验证码")
def send_verification_code(
    current_user: User = Depends(deps.get_current_active_user),
):
    """发送验证码给当前登录的超级管理员手机，用于创建/吊销 Key 时校验。"""
    _ensure_super_admin(current_user)
    SmsService.send_code(current_user.mobile)
    logger.info(f"发送 API Key 短信验证码: {current_user.mobile}")
    return {"message": "验证码已发送"}


@router.get("/", response_model=AdminApiKeyList, summary="API Key 列表")
def list_keys(
    skip: int = 0,
    limit: int = 50,
    keyword: Optional[str] = None,
    status_filter: Optional[str] = None,
    db: Session = Depends(deps.get_db),
    current_user: User = Depends(deps.get_current_active_user),
):
    _ensure_super_admin(current_user)

    query = db.query(AdminApiKey).options(joinedload(AdminApiKey.creator))

    if keyword:
        kw = f"%{keyword.strip()}%"
        query = query.filter(
            (AdminApiKey.name.ilike(kw)) | (AdminApiKey.key_prefix.ilike(kw))
        )

    if status_filter == "active":
        query = query.filter(
            AdminApiKey.is_active.is_(True),
            AdminApiKey.is_revoked.is_(False),
        )
    elif status_filter == "disabled":
        query = query.filter(
            AdminApiKey.is_active.is_(False),
            AdminApiKey.is_revoked.is_(False),
        )
    elif status_filter == "revoked":
        query = query.filter(AdminApiKey.is_revoked.is_(True))

    total = query.count()
    items = (
        query.order_by(AdminApiKey.id.desc())
        .offset(skip)
        .limit(limit)
        .all()
    )
    return {"total": total, "items": items}


@router.get("/{key_id}", response_model=AdminApiKeyResponse, summary="API Key 详情")
def get_key(
    key_id: int,
    db: Session = Depends(deps.get_db),
    current_user: User = Depends(deps.get_current_active_user),
):
    _ensure_super_admin(current_user)
    key = (
        db.query(AdminApiKey)
        .options(joinedload(AdminApiKey.creator))
        .filter(AdminApiKey.id == key_id)
        .first()
    )
    if not key:
        raise HTTPException(status_code=404, detail="Key 不存在")
    return key


@router.post("/", response_model=AdminApiKeySecretDisplay, summary="创建 API Key")
def create_key(
    *,
    body: AdminApiKeyCreate,
    request: Request,
    db: Session = Depends(deps.get_db),
    current_user: User = Depends(deps.get_current_active_user),
):
    """创建 Key。需要操作者密码 + 短信验证码。明文 Key 只在响应中返回一次。"""
    _ensure_super_admin(current_user)

    if not security.verify_password(body.admin_password, current_user.password_hash):
        logger.warning(f"创建 API Key 失败: 密码错误 (Admin: {current_user.mobile})")
        raise HTTPException(status_code=403, detail="管理员密码错误")

    if not SmsService.verify_code(current_user.mobile, body.sms_code):
        logger.warning(f"创建 API Key 失败: 短信验证码错误 (Admin: {current_user.mobile})")
        raise HTTPException(status_code=400, detail="验证码错误或已过期")

    plain_key = _generate_plain_key()
    key_prefix = plain_key[:KEY_PREFIX_LEN]
    key_hash = security.get_password_hash(plain_key)

    new_key = AdminApiKey(
        name=body.name.strip(),
        description=body.description,
        key_prefix=key_prefix,
        key_hash=key_hash,
        scopes=body.scopes,
        is_active=True,
        is_revoked=False,
        created_by=current_user.id,
    )
    db.add(new_key)
    db.commit()
    db.refresh(new_key)

    LogService.create_log(
        db=db,
        operator_id=current_user.id,
        action_type=ActionType.API_KEY_CREATE,
        ip_address=get_client_ip(request),
        details={
            "key_id": new_key.id,
            "key_prefix": new_key.key_prefix,
            "name": new_key.name,
            "scopes": new_key.scopes,
        },
    )
    logger.info(
        f"创建 API Key: {new_key.name} (prefix={new_key.key_prefix}, by={current_user.mobile})"
    )

    serialized = _serialize(db, new_key)
    base = AdminApiKeyResponse.model_validate(serialized).model_dump()
    return AdminApiKeySecretDisplay(**base, key_once=plain_key)


@router.put("/{key_id}", response_model=AdminApiKeyResponse, summary="编辑 API Key")
def update_key(
    key_id: int,
    body: AdminApiKeyUpdate,
    request: Request,
    db: Session = Depends(deps.get_db),
    current_user: User = Depends(deps.get_current_active_user),
):
    _ensure_super_admin(current_user)

    key = db.query(AdminApiKey).filter(AdminApiKey.id == key_id).first()
    if not key:
        raise HTTPException(status_code=404, detail="Key 不存在")
    if key.is_revoked:
        raise HTTPException(status_code=400, detail="已吊销的 Key 不可编辑")

    changes = {}
    if body.name is not None and body.name != key.name:
        changes["name"] = {"old": key.name, "new": body.name}
        key.name = body.name.strip()
    if body.description is not None and body.description != key.description:
        changes["description"] = {"old": key.description, "new": body.description}
        key.description = body.description
    if body.scopes is not None and body.scopes != key.scopes:
        changes["scopes"] = {"old": key.scopes, "new": body.scopes}
        key.scopes = body.scopes

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

    db.add(key)
    db.commit()
    db.refresh(key)

    LogService.create_log(
        db=db,
        operator_id=current_user.id,
        action_type=ActionType.API_KEY_UPDATE,
        ip_address=get_client_ip(request),
        details={
            "key_id": key.id,
            "key_prefix": key.key_prefix,
            "changes": changes,
        },
    )
    logger.info(f"更新 API Key: {key.name} (prefix={key.key_prefix})")

    return _serialize(db, key)


@router.post("/{key_id}/disable", response_model=AdminApiKeyResponse, summary="禁用 API Key")
def disable_key(
    key_id: int,
    request: Request,
    db: Session = Depends(deps.get_db),
    current_user: User = Depends(deps.get_current_active_user),
):
    _ensure_super_admin(current_user)
    key = db.query(AdminApiKey).filter(AdminApiKey.id == key_id).first()
    if not key:
        raise HTTPException(status_code=404, detail="Key 不存在")
    if key.is_revoked:
        raise HTTPException(status_code=400, detail="已吊销的 Key 不可操作")
    if not key.is_active:
        raise HTTPException(status_code=400, detail="Key 已是禁用状态")

    key.is_active = False
    db.add(key)
    db.commit()
    db.refresh(key)

    LogService.create_log(
        db=db,
        operator_id=current_user.id,
        action_type=ActionType.API_KEY_DISABLE,
        ip_address=get_client_ip(request),
        details={"key_id": key.id, "key_prefix": key.key_prefix},
    )
    logger.info(f"禁用 API Key: {key.name} (prefix={key.key_prefix})")
    return _serialize(db, key)


@router.post("/{key_id}/enable", response_model=AdminApiKeyResponse, summary="启用 API Key")
def enable_key(
    key_id: int,
    request: Request,
    db: Session = Depends(deps.get_db),
    current_user: User = Depends(deps.get_current_active_user),
):
    _ensure_super_admin(current_user)
    key = db.query(AdminApiKey).filter(AdminApiKey.id == key_id).first()
    if not key:
        raise HTTPException(status_code=404, detail="Key 不存在")
    if key.is_revoked:
        raise HTTPException(status_code=400, detail="已吊销的 Key 无法恢复")
    if key.is_active:
        raise HTTPException(status_code=400, detail="Key 已是启用状态")

    key.is_active = True
    db.add(key)
    db.commit()
    db.refresh(key)

    LogService.create_log(
        db=db,
        operator_id=current_user.id,
        action_type=ActionType.API_KEY_ENABLE,
        ip_address=get_client_ip(request),
        details={"key_id": key.id, "key_prefix": key.key_prefix},
    )
    logger.info(f"启用 API Key: {key.name} (prefix={key.key_prefix})")
    return _serialize(db, key)


@router.post("/{key_id}/revoke", response_model=AdminApiKeyResponse, summary="吊销 API Key（不可恢复）")
def revoke_key(
    key_id: int,
    body: AdminApiKeyRevoke,
    request: Request,
    db: Session = Depends(deps.get_db),
    current_user: User = Depends(deps.get_current_active_user),
):
    _ensure_super_admin(current_user)

    if not security.verify_password(body.admin_password, current_user.password_hash):
        logger.warning(f"吊销 API Key 失败: 密码错误 (Admin: {current_user.mobile})")
        raise HTTPException(status_code=403, detail="管理员密码错误")
    if not SmsService.verify_code(current_user.mobile, body.sms_code):
        logger.warning(f"吊销 API Key 失败: 短信验证码错误 (Admin: {current_user.mobile})")
        raise HTTPException(status_code=400, detail="验证码错误或已过期")

    key = db.query(AdminApiKey).filter(AdminApiKey.id == key_id).first()
    if not key:
        raise HTTPException(status_code=404, detail="Key 不存在")
    if key.is_revoked:
        raise HTTPException(status_code=400, detail="Key 已吊销")

    key.is_revoked = True
    key.is_active = False
    db.add(key)
    db.commit()
    db.refresh(key)

    LogService.create_log(
        db=db,
        operator_id=current_user.id,
        action_type=ActionType.API_KEY_REVOKE,
        ip_address=get_client_ip(request),
        details={"key_id": key.id, "key_prefix": key.key_prefix},
    )
    logger.info(f"吊销 API Key: {key.name} (prefix={key.key_prefix})")
    return _serialize(db, key)
