#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：security.py
模块描述：安全测试 API 路由

作者：czj
创建日期：2026-07-21
最后修改：2026-07-21
"""

import logging
import os
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.ext.asyncio import AsyncSession

from app.database import get_db
from app.schemas.security import (
    SecurityConfigCreate,
    SecurityConfigUpdate,
    SecurityConfigResponse,
    SecurityExecutionCreate,
    SecurityExecutionResponse,
    VulnerabilityResultResponse,
    AccountTestRequest,
    AccountTestResponse,
    KnowledgeBaseResponse,
    HistoricalVuln,
    HuaweiRedlineCheck,
)
from app.services.security_service import SecurityService

logger = logging.getLogger(__name__)

router = APIRouter()


# ==================== 配置管理 ====================

@router.get("/config", summary="获取安全测试配置列表")
async def list_configs(
    skip: int = Query(0, ge=0, description="跳过记录数"),
    limit: int = Query(20, ge=1, le=100, description="返回记录数"),
    db: AsyncSession = Depends(get_db)
):
    """
    获取安全测试配置列表

    Returns:
        dict: 配置列表和总数
    """
    service = SecurityService(db)
    configs, total = await service.list_configs(skip=skip, limit=limit)
    return {
        "items": [SecurityConfigResponse(**c.to_dict()) for c in configs],
        "total": total
    }


@router.get("/config/default", summary="获取默认安全测试配置")
async def get_default_config(db: AsyncSession = Depends(get_db)):
    """
    获取默认安全测试配置

    Returns:
        SecurityConfigResponse: 默认配置
    """
    service = SecurityService(db)
    config = await service.get_default_config()
    if not config:
        raise HTTPException(status_code=404, detail="未找到默认安全测试配置")
    return SecurityConfigResponse(**config.to_dict())


@router.get("/config/{config_id}", summary="获取指定安全测试配置")
async def get_config(
    config_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    获取指定安全测试配置

    Args:
        config_id: 配置ID

    Returns:
        SecurityConfigResponse: 配置详情
    """
    service = SecurityService(db)
    config = await service.get_config(config_id)
    if not config:
        raise HTTPException(status_code=404, detail=f"配置不存在: {config_id}")
    return SecurityConfigResponse(**config.to_dict())


@router.post("/config", summary="创建安全测试配置")
async def create_config(
    config_data: SecurityConfigCreate,
    db: AsyncSession = Depends(get_db)
):
    """
    创建安全测试配置

    Returns:
        SecurityConfigResponse: 创建的配置
    """
    service = SecurityService(db)
    config = await service.create_config(config_data.model_dump(by_alias=True))
    return SecurityConfigResponse(**config.to_dict())


@router.put("/config/{config_id}", summary="更新安全测试配置")
async def update_config(
    config_id: str,
    config_data: SecurityConfigUpdate,
    db: AsyncSession = Depends(get_db)
):
    """
    更新安全测试配置

    Args:
        config_id: 配置ID

    Returns:
        SecurityConfigResponse: 更新后的配置
    """
    service = SecurityService(db)
    config = await service.update_config(
        config_id,
        config_data.model_dump(by_alias=True, exclude_none=True)
    )
    if not config:
        raise HTTPException(status_code=404, detail=f"配置不存在: {config_id}")
    return SecurityConfigResponse(**config.to_dict())


@router.delete("/config/{config_id}", summary="删除安全测试配置")
async def delete_config(
    config_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    删除安全测试配置

    Args:
        config_id: 配置ID

    Returns:
        dict: 删除结果
    """
    service = SecurityService(db)
    success = await service.delete_config(config_id)
    if not success:
        raise HTTPException(status_code=404, detail=f"配置不存在: {config_id}")
    return {"message": "删除成功"}


# ==================== 账号测试 ====================

@router.post("/test-account", summary="测试账号连接")
async def test_account(
    request: AccountTestRequest,
    db: AsyncSession = Depends(get_db)
):
    """
    测试指定账号是否可以登录

    Returns:
        AccountTestResponse: 测试结果
    """
    service = SecurityService(db)
    result = await service.test_account(request.config_id, request.account_key)
    return AccountTestResponse(**result)


# ==================== 执行管理 ====================

@router.post("/executions", summary="创建安全测试执行")
async def create_execution(
    execution_data: SecurityExecutionCreate,
    db: AsyncSession = Depends(get_db)
):
    """
    创建安全测试执行

    Returns:
        SecurityExecutionResponse: 执行记录
    """
    service = SecurityService(db)

    execution = await service.create_execution(
        config_id=execution_data.config_id,
        module_ids=execution_data.module_ids,
        case_ids=execution_data.case_ids,
        name=execution_data.name,
    )

    return SecurityExecutionResponse(
        id=execution.id,
        name=execution.name,
        status=execution.status,
        total_cases=execution.total_cases,
        passed=execution.passed,
        failed=execution.failed,
        skipped=execution.skipped,
        duration=execution.duration,
        config_id=execution_data.config_id,
        start_time=execution.start_time.isoformat() if execution.start_time else None,
        end_time=execution.end_time.isoformat() if execution.end_time else None,
    )


@router.post("/executions/{execution_id}/run", summary="执行安全测试")
async def run_execution(
    execution_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    触发安全测试执行（异步）

    Args:
        execution_id: 执行ID

    Returns:
        dict: 执行状态
    """
    service = SecurityService(db)

    # 异步执行（不等待完成）
    import asyncio
    asyncio.create_task(service.run_execution(execution_id))

    return {
        "execution_id": execution_id,
        "status": "running",
        "message": "安全测试已开始执行"
    }


@router.get("/executions/{execution_id}/results", summary="获取安全测试结果")
async def get_execution_results(
    execution_id: str,
    skip: int = Query(0, ge=0),
    limit: int = Query(50, ge=1, le=200),
    level: Optional[str] = Query(None, description="风险等级筛选"),
    is_vulnerable: Optional[bool] = Query(None, description="是否漏洞"),
    db: AsyncSession = Depends(get_db)
):
    """
    获取安全测试执行结果

    Args:
        execution_id: 执行ID

    Returns:
        dict: 结果列表和总数
    """
    service = SecurityService(db)
    results, total = await service.get_vulnerability_results(
        execution_id=execution_id,
        skip=skip,
        limit=limit,
        level=level,
        is_vulnerable=is_vulnerable,
    )

    return {
        "items": [VulnerabilityResultResponse(**r.to_dict()) for r in results],
        "total": total
    }


@router.get("/executions/{execution_id}/summary", summary="获取安全测试摘要")
async def get_execution_summary(
    execution_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    获取安全测试执行摘要

    Args:
        execution_id: 执行ID

    Returns:
        dict: 摘要数据
    """
    service = SecurityService(db)
    return await service.get_execution_summary(execution_id)


# ==================== 知识库 ====================

@router.get("/knowledge-base", summary="获取安全知识库")
async def get_knowledge_base():
    """
    获取安全测试知识库内容

    Returns:
        KnowledgeBaseResponse: 知识库数据
    """
    try:
        from app.services.knowledge_base import KNOWLEDGE_BASE
    except ImportError:
        # 知识库模块尚未创建时返回空数据
        return KnowledgeBaseResponse()

    # 转换历史漏洞
    historical_vulns = []
    for v in KNOWLEDGE_BASE.get("historical_vulns", []):
        historical_vulns.append(HistoricalVuln(
            vuln_id=v.get("vuln_id", ""),
            title=v.get("title", ""),
            severity=v.get("severity", ""),
            vuln_type=v.get("vuln_type", ""),
            source_project=v.get("source_project", ""),
            detection_method=v.get("detection_method", ""),
            regression_note=v.get("regression_note", ""),
            mapped_paths=v.get("mapped_paths", []),
        ))

    # 转换华为红线
    huawei_redlines = []
    for r in KNOWLEDGE_BASE.get("huawei_redlines", []):
        huawei_redlines.append(HuaweiRedlineCheck(
            check_id=r.get("check_id", ""),
            category=r.get("category", ""),
            requirement=r.get("requirement", ""),
            severity=r.get("severity", ""),
            check_method=r.get("check_method", ""),
        ))

    return KnowledgeBaseResponse(
        historical_vulns=historical_vulns,
        huawei_redlines=huawei_redlines,
        total_vulns=len(historical_vulns),
        total_redlines=len(huawei_redlines),
    )


# ==================== 报告 ====================

@router.get("/executions/{execution_id}/report", summary="获取安全测试报告")
async def get_security_report(
    execution_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    获取安全测试 Markdown 报告内容

    Args:
        execution_id: 执行ID

    Returns:
        dict: 报告内容
    """
    from app.services.security_report_service import SecurityReportService

    try:
        report_service = SecurityReportService()
        markdown = await report_service.get_report_content(execution_id, db)
        return {
            "execution_id": execution_id,
            "content": markdown,
            "format": "markdown",
        }
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(f"获取安全测试报告失败: {e}")
        raise HTTPException(status_code=500, detail=f"获取报告失败: {str(e)}")


@router.get("/executions/{execution_id}/report/download", summary="下载安全测试报告")
async def download_security_report(
    execution_id: str,
    db: AsyncSession = Depends(get_db)
):
    """
    下载安全测试 Markdown 报告文件

    Args:
        execution_id: 执行ID

    Returns:
        FileResponse: 报告文件
    """
    from fastapi.responses import FileResponse
    from app.services.security_report_service import SecurityReportService

    try:
        report_service = SecurityReportService()
        file_path = await report_service.generate_report(execution_id, db)
        filename = os.path.basename(file_path)
        return FileResponse(
            file_path,
            media_type="text/markdown",
            filename=filename,
        )
    except ValueError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except Exception as e:
        logger.error(f"下载安全测试报告失败: {e}")
        raise HTTPException(status_code=500, detail=f"下载报告失败: {str(e)}")
