#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：cases.py
模块描述：测试用例管理 API 路由

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

import logging
from typing import Optional, List

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

from app.database import get_db
from app.schemas.test_case import (
    TestCaseCreate,
    TestCaseUpdate,
    TestCaseResponse,
    TestCaseListResponse,
    TestCaseImport,
)
from app.services.case_service import CaseService

logger = logging.getLogger(__name__)

router = APIRouter()


def _case_to_response(c) -> TestCaseResponse:
    """
    统一构造用例响应对象（包含 case_type 等所有字段）

    Args:
        c: TestCase ORM 对象

    Returns:
        TestCaseResponse: 用例响应
    """
    return TestCaseResponse(
        id=c.id,
        module_id=c.module_id,
        name=c.name,
        description=c.description,
        status=c.status,
        priority=c.priority,
        tags=c.tags or [],
        steps=c.steps or [],
        config=c.config or {},
        case_type=getattr(c, "case_type", None) or "ui",
        created_at=c.created_at,
        updated_at=c.updated_at,
    )


def get_case_service(db: AsyncSession = Depends(get_db)) -> CaseService:
    """
    获取用例服务实例（依赖注入）

    Args:
        db (AsyncSession): 数据库会话

    Returns:
        CaseService: 用例服务实例
    """
    return CaseService(db)


@router.get("", response_model=TestCaseListResponse)
async def list_cases(
    module_id: Optional[str] = Query(None, description="模块ID筛选"),
    keyword: Optional[str] = Query(None, description="关键词搜索"),
    status: Optional[str] = Query(None, description="状态筛选"),
    priority: Optional[str] = Query(None, description="优先级筛选"),
    case_type: Optional[str] = Query(None, description="用例类型筛选: ui/api/security/deploy"),
    skip: int = Query(0, ge=0, description="跳过记录数"),
    limit: int = Query(100, ge=1, le=500, description="返回记录数上限"),
    service: CaseService = Depends(get_case_service),
):
    """
    获取用例列表

    支持分页查询和按模块/关键词/状态/优先级/类型筛选。

    Args:
        module_id (Optional[str]): 模块ID筛选
        keyword (Optional[str]): 模糊搜索关键词
        status (Optional[str]): 状态过滤
        priority (Optional[str]): 优先级过滤
        case_type (Optional[str]): 用例类型过滤 ui/api/security/deploy
        skip (int): 跳过的记录数
        limit (int): 返回记录数上限
        service (CaseService): 用例服务实例

    Returns:
        TestCaseListResponse: 用例列表和总数
    """
    try:
        cases, total = await service.list(
            module_id=module_id,
            keyword=keyword,
            status=status,
            priority=priority,
            case_type=case_type,
            skip=skip,
            limit=limit,
        )

        items = [_case_to_response(c) for c in cases]

        return TestCaseListResponse(total=total, items=items)

    except Exception as e:
        logger.error(f"获取用例列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


@router.get("/{case_id}", response_model=TestCaseResponse)
async def get_case(
    case_id: str,
    service: CaseService = Depends(get_case_service),
):
    """
    获取单个用例详情

    Args:
        case_id (str): 用例ID
        service (CaseService): 用例服务实例

    Returns:
        TestCaseResponse: 用例详情

    Raises:
        HTTPException: 用例不存在时返回404
    """
    try:
        case = await service.get(case_id)
        if not case:
            raise HTTPException(status_code=404, detail=f"用例不存在: {case_id}")

        return _case_to_response(case)

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"获取用例详情失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


@router.post("", response_model=TestCaseResponse, status_code=201)
async def create_case(
    data: TestCaseCreate,
    service: CaseService = Depends(get_case_service),
):
    """
    创建测试用例

    Args:
        data (TestCaseCreate): 用例创建数据
        service (CaseService): 用例服务实例

    Returns:
        TestCaseResponse: 创建的用例信息

    Raises:
        HTTPException: 参数校验失败时返回400
    """
    try:
        case = await service.create(data)
        return _case_to_response(case)

    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"创建用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


@router.put("/{case_id}", response_model=TestCaseResponse)
async def update_case(
    case_id: str,
    data: TestCaseUpdate,
    service: CaseService = Depends(get_case_service),
):
    """
    更新测试用例

    只更新传入的非空字段。

    Args:
        case_id (str): 用例ID
        data (TestCaseUpdate): 更新数据
        service (CaseService): 用例服务实例

    Returns:
        TestCaseResponse: 更新后的用例信息

    Raises:
        HTTPException: 用例不存在时返回404
    """
    try:
        case = await service.update(case_id, data)
        if not case:
            raise HTTPException(status_code=404, detail=f"用例不存在: {case_id}")

        return _case_to_response(case)

    except HTTPException:
        raise
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))
    except Exception as e:
        logger.error(f"更新用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


@router.delete("/{case_id}", status_code=204)
async def delete_case(
    case_id: str,
    service: CaseService = Depends(get_case_service),
):
    """
    删除测试用例

    Args:
        case_id (str): 用例ID
        service (CaseService): 用例服务实例

    Raises:
        HTTPException: 用例不存在时返回404
    """
    try:
        deleted = await service.delete(case_id)
        if not deleted:
            raise HTTPException(status_code=404, detail=f"用例不存在: {case_id}")

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"删除用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


@router.post("/{case_id}/copy", response_model=TestCaseResponse, status_code=201)
async def copy_case(
    case_id: str,
    service: CaseService = Depends(get_case_service),
):
    """
    复制测试用例

    Args:
        case_id (str): 源用例ID
        service (CaseService): 用例服务实例

    Returns:
        TestCaseResponse: 复制的用例

    Raises:
        HTTPException: 源用例不存在时返回404
    """
    try:
        new_case = await service.copy(case_id)
        if not new_case:
            raise HTTPException(status_code=404, detail=f"用例不存在: {case_id}")

        return _case_to_response(new_case)

    except HTTPException:
        raise
    except Exception as e:
        logger.error(f"复制用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


@router.post("/import", response_model=dict)
async def import_cases(
    data: List[TestCaseImport],
    service: CaseService = Depends(get_case_service),
):
    """
    批量导入测试用例

    支持 JSON 格式批量导入，按 module_name 匹配或自动创建模块。

    Args:
        data (List[TestCaseImport]): 导入的用例数据列表
        service (CaseService): 用例服务实例

    Returns:
        dict: 导入结果统计
    """
    try:
        success, failed, errors = await service.import_cases(data)
        return {
            "success_count": success,
            "failed_count": failed,
            "errors": errors,
        }

    except Exception as e:
        logger.error(f"导入用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")


@router.post("/export", response_model=List[dict])
async def export_cases(
    case_ids: Optional[List[str]] = None,
    service: CaseService = Depends(get_case_service),
):
    """
    导出测试用例

    导出指定ID的用例，不指定则导出全部。

    Args:
        case_ids (Optional[List[str]]): 要导出的用例ID列表
        service (CaseService): 用例服务实例

    Returns:
        List[dict]: 用例数据列表
    """
    try:
        return await service.export_cases(case_ids)
    except Exception as e:
        logger.error(f"导出用例失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"服务器内部错误: {str(e)}")