"""
Batch Executor

批量执行器 - 负责批量执行剧集创作，支持质量检查和自动重试
"""
from typing import List, Dict, Any, Optional, Callable, Awaitable
from datetime import datetime
import asyncio
import uuid

from app.models.project import SeriesProject, Episode, EpisodeIssue
from app.models.review import ReviewConfig, ReviewResult
from app.core.agents.series_creation_agent import get_series_agent
from app.core.review.review_manager import get_review_manager, ReviewManager
from app.core.memory.memory_manager import get_memory_manager, MemoryManager
from app.db.repositories import episode_repo, project_repo
from app.utils.logger import get_logger

logger = get_logger(__name__)


class BatchExecutionStatus:
    """批量执行状态"""

    def __init__(
        self,
        batch_id: str,
        project_id: str,
        start_episode: int,
        end_episode: int
    ):
        self.batch_id = batch_id
        self.project_id = project_id
        self.start_episode = start_episode
        self.end_episode = end_episode
        self.total_episodes = end_episode - start_episode + 1

        # 执行状态
        self.status = "running"  # running, completed, stopped, failed
        self.current_episode = start_episode
        self.completed_episodes = 0
        self.failed_episodes = 0

        # 结果追踪
        self.episode_results: Dict[int, Dict[str, Any]] = {}
        self.start_time = datetime.now()
        self.end_time: Optional[datetime] = None

        # 回调函数
        self.on_progress: Optional[Callable] = None
        self.on_episode_complete: Optional[Callable] = None
        self.on_error: Optional[Callable] = None


class BatchExecutor:
    """
    批量执行器

    核心功能：
    1. 批量执行剧集创作
    2. 集成质量检查
    3. 自动重试失败剧集
    4. 生成执行摘要
    5. 实时进度通知
    """

    def __init__(
        self,
        review_manager: Optional[ReviewManager] = None,
        memory_manager: Optional[MemoryManager] = None
    ):
        """
        初始化批量执行器

        Args:
            review_manager: 审核管理器（可选）
            memory_manager: 记忆管理器（可选）
        """
        self.series_agent = get_series_agent()
        self.review_manager = review_manager or get_review_manager()
        self.memory_manager = memory_manager or get_memory_manager()

        # 执行状态追踪
        self.active_batches: Dict[str, BatchExecutionStatus] = {}
        self._stop_flags: Dict[str, bool] = {}

        logger.info("批量执行器初始化完成")

    async def execute_batch(
        self,
        project: SeriesProject,
        start_episode: int,
        end_episode: int,
        review_config: Optional[ReviewConfig] = None,
        enable_retry: bool = True,
        max_retries: int = 2,
        on_progress: Optional[Callable[[Dict[str, Any]], Awaitable[None]]] = None,
        on_episode_complete: Optional[Callable[[Dict[str, Any]], Awaitable[None]]] = None,
        on_error: Optional[Callable[[Dict[str, Any]], Awaitable[None]]] = None
    ) -> Dict[str, Any]:
        """
        执行批量剧集创作

        Args:
            project: 剧集项目
            start_episode: 起始集数
            end_episode: 结束集数
            review_config: 审核配置（可选，不提供则使用项目配置）
            enable_retry: 是否启用自动重试
            max_retries: 最大重试次数
            on_progress: 进度回调函数
            on_episode_complete: 剧集完成回调
            on_error: 错误回调

        Returns:
            执行结果摘要
        """
        batch_id = str(uuid.uuid4())
        logger.info(f"开始批量执行: {batch_id}, EP{start_episode}-{end_episode}")

        # 创建执行状态
        execution_status = BatchExecutionStatus(
            batch_id=batch_id,
            project_id=project.id,
            start_episode=start_episode,
            end_episode=end_episode
        )
        execution_status.on_progress = on_progress
        execution_status.on_episode_complete = on_episode_complete
        execution_status.on_error = on_error

        self.active_batches[batch_id] = execution_status
        self._stop_flags[batch_id] = False

        try:
            # 遍历执行每一集
            for episode_num in range(start_episode, end_episode + 1):
                # 检查是否停止
                if self._stop_flags.get(batch_id, False):
                    logger.info(f"批量执行被用户停止: {batch_id}")
                    execution_status.status = "stopped"
                    break

                execution_status.current_episode = episode_num

                try:
                    # 执行单集创作
                    episode_result = await self._execute_single_episode(
                        project=project,
                        episode_number=episode_num,
                        review_config=review_config,
                        enable_retry=enable_retry,
                        max_retries=max_retries,
                        batch_id=batch_id
                    )

                    # 记录结果
                    execution_status.episode_results[episode_num] = episode_result
                    execution_status.completed_episodes += 1

                    # 保存剧集
                    await episode_repo.create(episode_result["episode"])

                    # 通知进度
                    if on_progress:
                        await self._send_progress_update(execution_status, episode_result)

                    # 通知剧集完成
                    if on_episode_complete:
                        await on_episode_complete(episode_result)

                    logger.info(
                        f"EP{episode_num} 完成: "
                        f"质量分数={episode_result.get('quality_score', 0)}, "
                        f"通过={episode_result.get('passed', False)}"
                    )

                except Exception as e:
                    logger.error(f"EP{episode_num} 执行失败: {str(e)}")
                    execution_status.failed_episodes += 1

                    error_result = {
                        "episode_number": episode_num,
                        "success": False,
                        "error": str(e),
                        "batch_id": batch_id
                    }

                    execution_status.episode_results[episode_num] = error_result

                    if on_error:
                        await on_error(error_result)

            # 更新项目记忆
            await project_repo.update(project.id, {
                "memory": project.memory.dict(),
                "updatedAt": datetime.now()
            })

            # 完成批量执行
            execution_status.status = "completed"
            execution_status.end_time = datetime.now()

            # 生成摘要
            summary = await self._generate_summary(execution_status, project)

            logger.info(
                f"批量执行完成: {batch_id}, "
                f"成功={summary['successful']}, "
                f"失败={summary['failed']}, "
                f"耗时={summary['duration_seconds']:.1f}秒"
            )

            return summary

        except Exception as e:
            logger.error(f"批量执行异常: {str(e)}")
            execution_status.status = "failed"
            execution_status.end_time = datetime.now()

            return {
                "batch_id": batch_id,
                "success": False,
                "error": str(e),
                "project_id": project.id,
                "start_episode": start_episode,
                "end_episode": end_episode
            }

        finally:
            # 清理
            if batch_id in self._stop_flags:
                del self._stop_flags[batch_id]

    async def _execute_single_episode(
        self,
        project: SeriesProject,
        episode_number: int,
        review_config: Optional[ReviewConfig],
        enable_retry: bool,
        max_retries: int,
        batch_id: str
    ) -> Dict[str, Any]:
        """
        执行单集创作（包含质量检查和重试）

        Args:
            project: 项目
            episode_number: 集数
            review_config: 审核配置
            enable_retry: 是否启用重试
            max_retries: 最大重试次数
            batch_id: 批次ID

        Returns:
            执行结果
        """
        retry_count = 0
        last_result = None
        feedback_history: List[str] = []

        while retry_count <= max_retries:
            try:
                # 1. 执行创作
                logger.info(f"创作 EP{episode_number} (尝试 {retry_count + 1}/{max_retries + 1})")

                # 如果有反馈历史，添加到上下文
                if feedback_history:
                    # 使用反馈作为额外上下文（在真实实现中会传递给 Agent）
                    logger.info(f"使用 {len(feedback_history)} 条反馈进行重试")

                episode = await self.series_agent.execute_episode(
                    project=project,
                    episode_number=episode_number,
                    title=f"第{episode_number}集内容创作"
                )

                # 2. 更新记忆系统
                if episode.content:
                    await self.memory_manager.update_memory_from_episode(project, episode)

                # 3. 执行质量检查
                review_passed = True
                review_result = None
                quality_score = episode.qualityScore or 0

                if review_config:
                    # 从项目获取审核配置
                    from app.models.review import ReviewConfig as RC
                    config = review_config or RC()

                    review_result = await self.review_manager.review_episode(
                        project=project,
                        episode=episode,
                        config=config
                    )

                    review_passed = review_result.passed
                    quality_score = review_result.overall_score
                    episode.qualityScore = quality_score
                    episode.issues = [
                        EpisodeIssue(
                            type=issue.type.value,
                            description=issue.description,
                            severity=issue.severity.value,
                            suggestion=issue.suggestion
                        )
                        for issue in review_result.issues
                    ]

                # 4. 判断是否需要重试
                if review_passed or not enable_retry or retry_count >= max_retries:
                    # 成功或达到最大重试次数
                    episode.status = "completed" if review_passed else "needs-review"
                    episode.completedAt = datetime.now()
                    episode.retryCount = retry_count

                    return {
                        "episode_number": episode_number,
                        "success": review_passed or retry_count >= max_retries,
                        "episode": episode.dict(),
                        "quality_score": quality_score,
                        "passed": review_passed,
                        "retry_count": retry_count,
                        "review_result": review_result.dict() if review_result else None,
                        "batch_id": batch_id
                    }

                # 5. 准备重试
                logger.warning(
                    f"EP{episode_number} 未通过质量检查 (分数: {quality_score:.1f}), "
                    f"准备重试..."
                )

                # 构建反馈
                feedback = await self._build_feedback_from_review(review_result)
                feedback_history.append(feedback)

                retry_count += 1

            except Exception as e:
                logger.error(f"EP{episode_number} 创作失败 (尝试 {retry_count + 1}): {str(e)}")

                if retry_count >= max_retries:
                    # 达到最大重试次数，返回失败结果
                    return {
                        "episode_number": episode_number,
                        "success": False,
                        "error": str(e),
                        "retry_count": retry_count,
                        "batch_id": batch_id,
                        "episode": None
                    }

                retry_count += 1

        # 不应该到达这里
        return {
            "episode_number": episode_number,
            "success": False,
            "error": "未知错误",
            "batch_id": batch_id
        }

    async def _build_feedback_from_review(self, review_result: ReviewResult) -> str:
        """
        从审核结果构建反馈信息

        Args:
            review_result: 审核结果

        Returns:
            反馈文本
        """
        feedback_parts = []

        feedback_parts.append(f"质量分数: {review_result.overall_score:.1f}/100")

        if review_result.issues:
            feedback_parts.append(f"\n发现 {len(review_result.issues)} 个问题:")

            # 按严重程度分组
            high_issues = [i for i in review_result.issues if i.severity.value == "high"]
            medium_issues = [i for i in review_result.issues if i.severity.value == "medium"]
            low_issues = [i for i in review_result.issues if i.severity.value == "low"]

            if high_issues:
                feedback_parts.append("\n【高严重度问题】")
                for issue in high_issues[:3]:  # 限制数量
                    feedback_parts.append(f"- {issue.description}")
                    if issue.suggestion:
                        feedback_parts.append(f"  建议: {issue.suggestion}")

            if medium_issues:
                feedback_parts.append("\n【中严重度问题】")
                for issue in medium_issues[:3]:
                    feedback_parts.append(f"- {issue.description}")

        return "\n".join(feedback_parts)

    async def _send_progress_update(
        self,
        execution_status: BatchExecutionStatus,
        episode_result: Dict[str, Any]
    ):
        """
        发送进度更新

        Args:
            execution_status: 执行状态
            episode_result: 剧集结果
        """
        progress = {
            "batch_id": execution_status.batch_id,
            "project_id": execution_status.project_id,
            "current_episode": execution_status.current_episode,
            "total_episodes": execution_status.total_episodes,
            "completed_episodes": execution_status.completed_episodes,
            "failed_episodes": execution_status.failed_episodes,
            "progress_percentage": (
                execution_status.completed_episodes / execution_status.total_episodes * 100
            ),
            "current_episode_result": episode_result,
            "timestamp": datetime.now().isoformat()
        }

        if execution_status.on_progress:
            await execution_status.on_progress(progress)

    async def _generate_summary(
        self,
        execution_status: BatchExecutionStatus,
        project: SeriesProject
    ) -> Dict[str, Any]:
        """
        生成批量执行摘要

        Args:
            execution_status: 执行状态
            project: 项目

        Returns:
            执行摘要
        """
        # 计算统计信息
        successful = sum(
            1 for r in execution_status.episode_results.values()
            if r.get("success", False)
        )
        failed = execution_status.failed_episodes

        # 计算质量分数统计
        quality_scores = [
            r.get("quality_score", 0)
            for r in execution_status.episode_results.values()
            if r.get("quality_score") is not None
        ]

        avg_quality = sum(quality_scores) / len(quality_scores) if quality_scores else 0
        min_quality = min(quality_scores) if quality_scores else 0
        max_quality = max(quality_scores) if quality_scores else 0

        # 计算耗时
        duration = (
            execution_status.end_time - execution_status.start_time
        ).total_seconds() if execution_status.end_time else 0

        # 构建摘要
        summary = {
            "batch_id": execution_status.batch_id,
            "project_id": execution_status.project_id,
            "project_name": project.name,
            "status": execution_status.status,
            "start_episode": execution_status.start_episode,
            "end_episode": execution_status.end_episode,
            "total_episodes": execution_status.total_episodes,
            "successful": successful,
            "failed": failed,
            "success_rate": successful / execution_status.total_episodes if execution_status.total_episodes > 0 else 0,
            "quality_stats": {
                "average": avg_quality,
                "min": min_quality,
                "max": max_quality
            },
            "duration_seconds": duration,
            "start_time": execution_status.start_time.isoformat(),
            "end_time": execution_status.end_time.isoformat() if execution_status.end_time else None,
            "episode_results": execution_status.episode_results
        }

        return summary

    async def stop_batch(self, batch_id: str) -> bool:
        """
        停止批量执行

        Args:
            batch_id: 批次ID

        Returns:
            是否成功停止
        """
        if batch_id in self.active_batches:
            self._stop_flags[batch_id] = True
            logger.info(f"已发送停止信号: {batch_id}")
            return True
        return False

    def get_batch_status(self, batch_id: str) -> Optional[Dict[str, Any]]:
        """
        获取批量执行状态

        Args:
            batch_id: 批次ID

        Returns:
            执行状态信息
        """
        execution_status = self.active_batches.get(batch_id)
        if not execution_status:
            return None

        return {
            "batch_id": execution_status.batch_id,
            "project_id": execution_status.project_id,
            "status": execution_status.status,
            "current_episode": execution_status.current_episode,
            "total_episodes": execution_status.total_episodes,
            "completed_episodes": execution_status.completed_episodes,
            "failed_episodes": execution_status.failed_episodes,
            "progress_percentage": (
                execution_status.completed_episodes / execution_status.total_episodes * 100
                if execution_status.total_episodes > 0 else 0
            ),
            "start_time": execution_status.start_time.isoformat(),
            "end_time": execution_status.end_time.isoformat() if execution_status.end_time else None
        }


# 全局单例
_batch_executor: Optional[BatchExecutor] = None


def get_batch_executor() -> BatchExecutor:
    """获取批量执行器单例"""
    global _batch_executor
    if _batch_executor is None:
        _batch_executor = BatchExecutor()
    return _batch_executor
