#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：batch_service.py
模块描述：批量操作服务

作者：czj
创建日期：2026-07-12
"""

import logging
from typing import List, Dict, Any, Tuple

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete, update

from app.models.test_case import TestCase
from app.models.case_result import CaseResult
from app.utils.id_generator import generate_id

logger = logging.getLogger(__name__)


class BatchService:
    """
    批量操作服务

    负责测试用例的批量操作，包括：
    - 批量删除
    - 批量更新
    - 批量复制
    - 批量分配标签
    - 批量设置优先级

    Attributes:
        db (AsyncSession): 数据库会话对象

    Example:
        >>> service = BatchService(db)
        >>> result = await service.batch_delete(["case_001", "case_002"])
    """

    def __init__(self, db: AsyncSession):
        """
        初始化批量操作服务

        Args:
            db (AsyncSession): 数据库会话对象
        """
        if db is None:
            raise ValueError("数据库会话不能为空")
        self.db = db

    async def batch_delete(self, case_ids: List[str]) -> Dict[str, int]:
        """
        批量删除用例

        Args:
            case_ids (List[str]): 用例ID列表

        Returns:
            Dict[str, int]: 操作结果
                {"success": 成功数量, "failed": 失败数量}
        """
        try:
            # 检查用例是否存在
            query = select(TestCase.id).where(TestCase.id.in_(case_ids))
            result = await self.db.execute(query)
            existing_ids = set(result.scalars().all())

            # 找出不存在的用例
            missing_ids = set(case_ids) - existing_ids
            if missing_ids:
                logger.warning(f"以下用例不存在: {missing_ids}")

            # 删除存在的用例（级联删除依赖关系和执行结果）
            delete_query = delete(TestCase).where(TestCase.id.in_(existing_ids))
            delete_result = await self.db.execute(delete_query)

            await self.db.flush()

            success_count = delete_result.rowcount
            failed_count = len(case_ids) - success_count

            logger.info(f"批量删除完成: 成功={success_count}, 失败={failed_count}")

            return {
                "success": success_count,
                "failed": failed_count,
                "total": len(case_ids)
            }

        except Exception as e:
            logger.error(f"批量删除失败: {str(e)}")
            raise

    async def batch_update(
        self,
        case_ids: List[str],
        updates: Dict[str, Any]
    ) -> Dict[str, int]:
        """
        批量更新用例

        Args:
            case_ids (List[str]): 用例ID列表
            updates (Dict[str, Any]): 更新字段
                {"priority": "high", "status": "active"}

        Returns:
            Dict[str, int]: 操作结果
                {"success": 成功数量, "failed": 失败数量}
        """
        try:
            # 验证更新字段
            allowed_fields = {"status", "priority", "tags", "order", "config"}
            invalid_fields = set(updates.keys()) - allowed_fields

            if invalid_fields:
                raise ValueError(f"不允许批量更新以下字段: {invalid_fields}")

            # 执行批量更新
            update_query = (
                update(TestCase)
                .where(TestCase.id.in_(case_ids))
                .values(**updates)
            )
            update_result = await self.db.execute(update_query)

            await self.db.flush()

            success_count = update_result.rowcount
            failed_count = len(case_ids) - success_count

            logger.info(f"批量更新完成: 成功={success_count}, 失败={failed_count}")

            return {
                "success": success_count,
                "failed": failed_count,
                "total": len(case_ids)
            }

        except Exception as e:
            logger.error(f"批量更新失败: {str(e)}")
            raise

    async def batch_copy(
        self,
        case_ids: List[str],
        target_module_id: str = None
    ) -> Tuple[List[TestCase], Dict[str, Any]]:
        """
        批量复制用例

        Args:
            case_ids (List[str]): 用例ID列表
            target_module_id (str, optional): 目标模块ID，不指定则复制到原模块

        Returns:
            Tuple[List[TestCase], Dict[str, Any]]: (新用例列表, 统计信息)
        """
        try:
            # 查询源用例
            query = select(TestCase).where(TestCase.id.in_(case_ids))
            result = await self.db.execute(query)
            source_cases = list(result.scalars().all())

            new_cases = []
            failed_count = 0

            for source in source_cases:
                try:
                    # 创建新用例
                    new_case = TestCase(
                        id=generate_id("case"),
                        module_id=target_module_id or source.module_id,
                        name=f"{source.name}(副本)",
                        description=source.description,
                        status=source.status,
                        priority=source.priority,
                        tags=source.tags.copy() if source.tags else [],
                        steps=source.steps.copy() if source.steps else [],
                        config=source.config.copy() if source.config else {},
                        depends_on=source.depends_on.copy() if source.depends_on else [],
                        parameters=source.parameters.copy() if source.parameters else {},
                        condition=source.condition.copy() if source.condition else {},
                        order=source.order,
                        version=1,  # 新用例版本为1
                    )

                    self.db.add(new_case)
                    new_cases.append(new_case)

                except Exception as e:
                    logger.error(f"复制用例失败: {source.id}, 错误: {str(e)}")
                    failed_count += 1

            await self.db.flush()

            logger.info(f"批量复制完成: 成功={len(new_cases)}, 失败={failed_count}")

            stats = {
                "success": len(new_cases),
                "failed": failed_count,
                "total": len(case_ids)
            }

            return new_cases, stats

        except Exception as e:
            logger.error(f"批量复制失败: {str(e)}")
            raise

    async def batch_assign_tags(
        self,
        case_ids: List[str],
        tag_names: List[str]
    ) -> Dict[str, int]:
        """
        批量分配标签

        Args:
            case_ids (List[str]): 用例ID列表
            tag_names (List[str]): 标签名称列表

        Returns:
            Dict[str, int]: 操作结果
                {"success": 成功数量, "failed": 失败数量}
        """
        try:
            # 查询用例
            query = select(TestCase).where(TestCase.id.in_(case_ids))
            result = await self.db.execute(query)
            cases = list(result.scalars().all())

            success_count = 0

            for case in cases:
                # 合并标签（去重）
                existing_tags = set(case.tags or [])
                new_tags = existing_tags.union(set(tag_names))
                case.tags = list(new_tags)
                success_count += 1

            await self.db.flush()

            logger.info(f"批量分配标签完成: 成功={success_count}, 总数={len(case_ids)}")

            return {
                "success": success_count,
                "failed": len(case_ids) - success_count,
                "total": len(case_ids)
            }

        except Exception as e:
            logger.error(f"批量分配标签失败: {str(e)}")
            raise

    async def batch_set_priority(
        self,
        case_ids: List[str],
        priority: str
    ) -> Dict[str, int]:
        """
        批量设置优先级

        Args:
            case_ids (List[str]): 用例ID列表
            priority (str): 优先级 (high/medium/low)

        Returns:
            Dict[str, int]: 操作结果
        """
        if priority not in ["high", "medium", "low"]:
            raise ValueError(f"无效的优先级: {priority}")

        return await self.batch_update(case_ids, {"priority": priority})

    async def batch_enable(self, case_ids: List[str]) -> Dict[str, int]:
        """
        批量启用用例

        Args:
            case_ids (List[str]): 用例ID列表

        Returns:
            Dict[str, int]: 操作结果
        """
        return await self.batch_update(case_ids, {"status": "active"})

    async def batch_disable(self, case_ids: List[str]) -> Dict[str, int]:
        """
        批量禁用用例

        Args:
            case_ids (List[str]): 用例ID列表

        Returns:
            Dict[str, int]: 操作结果
        """
        return await self.batch_update(case_ids, {"status": "disabled"})

    async def batch_move_to_module(
        self,
        case_ids: List[str],
        target_module_id: str
    ) -> Dict[str, int]:
        """
        批量移动到指定模块

        Args:
            case_ids (List[str]): 用例ID列表
            target_module_id (str): 目标模块ID

        Returns:
            Dict[str, int]: 操作结果
        """
        from app.models.module import Module

        # 验证目标模块是否存在
        query = select(Module.id).where(Module.id == target_module_id)
        result = await self.db.execute(query)
        if not result.scalar_one_or_none():
            raise ValueError(f"目标模块不存在: {target_module_id}")

        return await self.batch_update(case_ids, {"module_id": target_module_id})
