"""后台系统配置与通知插件管理。"""

from typing import Any
import os
import tempfile
from pathlib import Path

from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession

from app.core.deps import require_role
from app.database import get_db
from app.models.user import User
from app.schemas.common import ApiResponse
from app.services import (
    email_service,
    notification_plugin_service,
    plugin_diagnostic_service,
    provider_loader,
    sms_service,
    system_setting_service,
)
from mode.verification.base import VerificationProviderError


router = APIRouter()
_admin = require_role("admin", "super_admin")
_super = require_role("super_admin")


class BusinessSettingsUpdate(BaseModel):
    values: dict[str, Any] = Field(default_factory=dict)


class PluginConfigUpdate(BaseModel):
    values: dict[str, Any] = Field(default_factory=dict)


class PluginTestRequest(BaseModel):
    target: str | None = None
    mode: str | None = None
    real_name: str | None = None
    id_card_no: str | None = None
    phone: str | None = None
    return_url: str | None = None
    values: dict[str, Any] = Field(default_factory=dict)


class PluginReloadRequest(BaseModel):
    install_dependencies: bool = True
    restart_backend: bool = True


async def _save_upload_to_temp(file: UploadFile) -> str:
    if not file.filename.lower().endswith(".zip"):
        raise HTTPException(status_code=400, detail="请上传 zip 插件包")
    fd, path = tempfile.mkstemp(prefix="qycw_plugin_upload_", suffix=".zip")
    try:
        with os.fdopen(fd, "wb") as buffer:
            while True:
                chunk = await file.read(1024 * 1024)
                if not chunk:
                    break
                buffer.write(chunk)
    except Exception:
        os.close(fd)
        raise
    finally:
        await file.close()
    return path


@router.get("/business-rules", response_model=ApiResponse)
async def get_business_rules(
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await system_setting_service.list_business_settings(db)
    return ApiResponse(data=data)


@router.put("/business-rules", response_model=ApiResponse)
async def update_business_rules(
    body: BusinessSettingsUpdate,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await system_setting_service.update_business_settings(db, body.values)
    return ApiResponse(data=data, message="业务规则配置已保存")


@router.get("/notification-plugins", response_model=ApiResponse)
async def list_notification_plugins(
    plugin_type: str | None = None,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    return ApiResponse(data=await notification_plugin_service.list_plugins_with_state(db, plugin_type))


@router.get("/plugin-diagnostics", response_model=ApiResponse)
async def get_plugin_diagnostics(
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    return ApiResponse(data=await plugin_diagnostic_service.build_plugin_diagnostics(db))


@router.post("/notification-plugins/preview", response_model=ApiResponse)
async def preview_notification_plugin(
    file: UploadFile = File(...),
    _: User = Depends(_admin),
):
    path = await _save_upload_to_temp(file)
    try:
        data = notification_plugin_service.preview_plugin_zip(Path(path))
    finally:
        os.remove(path)
    return ApiResponse(data=data)


@router.post("/notification-plugins/install", response_model=ApiResponse)
async def install_notification_plugin(
    overwrite: bool = Query(False),
    file: UploadFile = File(...),
    current_user: User = Depends(_super),
):
    path = await _save_upload_to_temp(file)
    try:
        data = notification_plugin_service.install_plugin_zip(Path(path), overwrite=overwrite, operator_id=current_user.id)
    finally:
        os.remove(path)
    return ApiResponse(data=data, message="插件已安装")


@router.post("/notification-plugins/reload", response_model=ApiResponse)
async def reload_notification_plugins(
    body: PluginReloadRequest,
    current_user: User = Depends(_super),
):
    data = await notification_plugin_service.apply_plugin_changes(
        install_dependencies=body.install_dependencies,
        restart_backend=body.restart_backend,
        operator_id=current_user.id,
    )
    return ApiResponse(data=data, message="插件变更已应用")


@router.get("/notification-plugins/{plugin_type}/{plugin_id}/config", response_model=ApiResponse)
async def get_notification_plugin_config(
    plugin_type: str,
    plugin_id: str,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    return ApiResponse(data=await notification_plugin_service.get_plugin_config(db, plugin_type, plugin_id))


@router.put("/notification-plugins/{plugin_type}/{plugin_id}/config", response_model=ApiResponse)
async def update_notification_plugin_config(
    plugin_type: str,
    plugin_id: str,
    body: PluginConfigUpdate,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await notification_plugin_service.save_plugin_config(db, plugin_type, plugin_id, body.values)
    return ApiResponse(data=data, message="插件配置已保存")


@router.post("/notification-plugins/{plugin_type}/{plugin_id}/enable", response_model=ApiResponse)
async def enable_notification_plugin(
    plugin_type: str,
    plugin_id: str,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await notification_plugin_service.enable_plugin(db, plugin_type, plugin_id)
    return ApiResponse(data=data, message="插件已启用")


@router.post("/notification-plugins/{plugin_type}/{plugin_id}/disable", response_model=ApiResponse)
async def disable_notification_plugin(
    plugin_type: str,
    plugin_id: str,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    data = await notification_plugin_service.disable_plugin(db, plugin_type, plugin_id)
    return ApiResponse(data=data, message="插件已禁用")


@router.post("/notification-plugins/{plugin_type}/{plugin_id}/test", response_model=ApiResponse)
async def test_notification_plugin(
    plugin_type: str,
    plugin_id: str,
    body: PluginTestRequest,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_admin),
):
    plugin = notification_plugin_service.get_plugin(plugin_type, plugin_id)
    values = dict(body.values)
    if plugin_type == "email":
        if not body.target:
            raise HTTPException(status_code=400, detail="请输入测试邮箱")
        values["notification.email.enabled"] = True
        values["notification.email.provider"] = str(plugin["provider"])
        await email_service.send_test_email(body.target, config_overrides=values)
        return ApiResponse(data={"sent": True}, message="测试发送已提交")
    elif plugin_type == "sms":
        if not body.target:
            raise HTTPException(status_code=400, detail="请输入测试手机号")
        values["notification.sms.enabled"] = True
        values["notification.sms.provider"] = str(plugin["provider"])
        await sms_service.send_test_sms(body.target, config_overrides=values)
        return ApiResponse(data={"sent": True}, message="测试发送已提交")
    elif plugin_type == "verification":
        capabilities = set(plugin.get("capabilities") or [])
        mode = (body.mode or "").strip() or ("two_factor" if "two_factor" in capabilities else "face_redirect")
        real_name = (body.real_name or "").strip()
        id_card_no = (body.id_card_no or "").strip().upper()
        if not real_name or not id_card_no:
            raise HTTPException(status_code=400, detail="请输入测试姓名和身份证号")

        values["verification.enabled"] = True
        values["verification.provider"] = str(plugin["provider"])
        values["verification.default_mode"] = mode
        config = await system_setting_service.get_verification_provider_config(db, overrides=values)
        try:
            provider = provider_loader.create_verification_provider(config)
            if mode == "two_factor":
                if "two_factor" not in capabilities:
                    raise HTTPException(status_code=400, detail="该插件不支持二要素测试")
                result = await provider.verify_two_factor(real_name=real_name, id_card_no=id_card_no)
                return ApiResponse(
                    data={
                        "mode": result.mode,
                        "passed": result.passed,
                        "status": result.status,
                        "reason": result.reason,
                        "external_id": result.external_id,
                        "raw": result.raw,
                    },
                    message="二要素测试已完成",
                )
            if mode == "three_factor":
                if "three_factor" not in capabilities:
                    raise HTTPException(status_code=400, detail="该插件不支持三要素测试")
                phone = (body.phone or "").strip()
                if not phone:
                    raise HTTPException(status_code=400, detail="请输入测试手机号")
                result = await provider.verify_three_factor(real_name=real_name, id_card_no=id_card_no, phone=phone)
                return ApiResponse(
                    data={
                        "mode": result.mode,
                        "passed": result.passed,
                        "status": result.status,
                        "reason": result.reason,
                        "external_id": result.external_id,
                        "raw": result.raw,
                    },
                    message="三要素测试已完成",
                )
            if mode == "face_redirect":
                if "face_redirect" not in capabilities:
                    raise HTTPException(status_code=400, detail="该插件不支持 H5 跳转测试")
                session = await provider.create_redirect_session(
                    real_name=real_name,
                    id_card_no=id_card_no,
                    return_url=(body.return_url or "https://example.com/verification-return").strip(),
                )
                return ApiResponse(
                    data={
                        "mode": "face_redirect",
                        "url": session.url,
                        "external_id": session.external_id,
                        "expires_in": session.expires_in,
                        "raw": session.raw,
                    },
                    message="H5 跳转测试链接已创建",
                )
        except VerificationProviderError as exc:
            raise HTTPException(status_code=exc.status_code, detail=exc.message) from exc
        raise HTTPException(status_code=400, detail="实名认证测试方式无效")
    else:
        raise HTTPException(status_code=400, detail="插件类型无效")


@router.delete("/notification-plugins/{plugin_type}/{plugin_id}", response_model=ApiResponse)
async def delete_notification_plugin(
    plugin_type: str,
    plugin_id: str,
    db: AsyncSession = Depends(get_db),
    _: User = Depends(_super),
):
    data = await notification_plugin_service.delete_plugin(db, plugin_type, plugin_id)
    return ApiResponse(data=data, message="插件已删除")
