"""
Retry Manager

自动重试管理器 - 负责判断是否需要重试以及执行重试逻辑
"""
from typing import List, Dict, Any, Optional
from datetime import datetime
import uuid

from app.models.project import SeriesProject, Episode, EpisodeIssue
from app.models.review import ReviewResult, ReviewIssue, SeverityLevel, DimensionType
from app.core.agents.series_creation_agent import get_series_agent
from app.core.memory.memory_manager import get_memory_manager
from app.utils.logger import get_logger

logger = get_logger(__name__)


class RetryConfig:
    """重试配置"""

    def __init__(
        self,
        max_retries: int = 2,
        retry_on_failure: bool = True,
        retry_on_low_quality: bool = True,
        quality_threshold: float = 75.0,
        retry_on_high_severity: bool = True,
        max_high_severity: int = 0
    ):
        self.max_retries = max_retries
        self.retry_on_failure = retry_on_failure
        self.retry_on_low_quality = retry_on_low_quality
        self.quality_threshold = quality_threshold
        self.retry_on_high_severity = retry_on_high_severity
        self.max_high_severity = max_high_severity


class RetryManager:
    """
    自动重试管理器

    核心功能：
    1. 判断剧集是否应该重试
    2. 执行剧集重试
    3. 从审核结果构建反馈
    4. 追踪重试历史
    """

    def __init__(self):
        """初始化重试管理器"""
        self.series_agent = get_series_agent()
        self.memory_manager = get_memory_manager()

        # 重试历史追踪
        self.retry_history: Dict[str, List[Dict[str, Any]]] = {}

        logger.info("自动重试管理器初始化完成")

    def should_retry(
        self,
        episode: Episode,
        review_result: Optional[ReviewResult] = None,
        config: Optional[RetryConfig] = None,
        current_retry_count: int = 0
    ) -> tuple[bool, str]:
        """
        判断剧集是否应该重试

        Args:
            episode: 剧集
            review_result: 审核结果（可选）
            config: 重试配置（可选）
            current_retry_count: 当前已重试次数

        Returns:
            (是否重试, 原因)
        """
        config = config or RetryConfig()

        # 检查重试次数限制
        if current_retry_count >= config.max_retries:
            return False, f"已达到最大重试次数 ({config.max_retries})"

        # 1. 检查执行失败
        if config.retry_on_failure and episode.status == "needs-review":
            # 检查是否有执行错误
            execution_errors = [
                issue for issue in episode.issues
                if issue.type == "execution_error"
            ]
            if execution_errors:
                return True, "执行失败，需要重试"

        # 2. 检查质量分数
        if review_result and config.retry_on_low_quality:
            if review_result.overall_score < config.quality_threshold:
                return True, (
                    f"质量分数 ({review_result.overall_score:.1f}) "
                    f"低于阈值 ({config.quality_threshold})"
                )

        # 3. 检查高严重度问题
        if review_result and config.retry_on_high_severity:
            high_count = review_result.high_severity_count
            if high_count > config.max_high_severity:
                return True, (
                    f"存在 {high_count} 个高严重度问题 "
                    f"(阈值: {config.max_high_severity})"
                )

        # 4. 检查特定维度未通过
        if review_result:
            failed_dimensions = [
                ds.dimension.value for ds in review_result.dimension_scores
                if not ds.passed
            ]
            if failed_dimensions:
                return True, f"以下维度未通过: {', '.join(failed_dimensions)}"

        # 不需要重试
        return False, "质量检查通过或不符合重试条件"

    async def retry_episode(
        self,
        project: SeriesProject,
        episode: Episode,
        review_result: Optional[ReviewResult] = None,
        feedback: Optional[str] = None,
        config: Optional[RetryConfig] = None
    ) -> Episode:
        """
        重试剧集创作

        Args:
            project: 项目
            episode: 原剧集
            review_result: 审核结果
            feedback: 反馈信息（可选，不提供则自动生成）
            config: 重试配置

        Returns:
            新创作的剧集
        """
        retry_count = episode.retryCount + 1
        logger.info(f"重试 EP{episode.number} (第 {retry_count} 次重试)")

        # 生成反馈
        if not feedback and review_result:
            feedback = await self._build_feedback(project, episode, review_result)

        # 记录重试历史
        retry_record = {
            "timestamp": datetime.now().isoformat(),
            "episode_number": episode.number,
            "retry_count": retry_count,
            "previous_score": episode.qualityScore,
            "feedback": feedback,
            "review_issues": [
                {
                    "type": issue.type.value,
                    "description": issue.description,
                    "severity": issue.severity.value,
                    "suggestion": issue.suggestion
                }
                for issue in (review_result.issues if review_result and review_result.issues else [])
            ]
        }

        if episode.id not in self.retry_history:
            self.retry_history[episode.id] = []
        self.retry_history[episode.id].append(retry_record)

        try:
            # 执行重试创作
            # 在真实实现中，会将反馈作为额外上下文传递给 Agent
            new_episode = await self.series_agent.execute_episode(
                project=project,
                episode_number=episode.number,
                title=episode.title or f"第{episode.number}集"
            )

            # 更新重试计数
            new_episode.retryCount = retry_count

            # 如果有内容，更新记忆
            if new_episode.content:
                await self.memory_manager.update_memory_from_episode(project, new_episode)

            logger.info(
                f"EP{episode.number} 重试完成: "
                f"新分数={new_episode.qualityScore}, "
                f"重试次数={retry_count}"
            )

            return new_episode

        except Exception as e:
            logger.error(f"重试 EP{episode.number} 失败: {str(e)}")

            # 返回失败状态
            episode.status = "needs-review"
            episode.issues.append(
                EpisodeIssue(
                    type="retry_error",
                    description=f"重试失败: {str(e)}",
                    severity="high"
                )
            )
            episode.retryCount = retry_count

            return episode

    async def _build_feedback(
        self,
        project: SeriesProject,
        episode: Episode,
        review_result: ReviewResult
    ) -> str:
        """
        构建重试反馈

        Args:
            project: 项目
            episode: 剧集
            review_result: 审核结果

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

        # 1. 总体评价
        feedback_parts.append(f"【质量评估】")
        feedback_parts.append(f"当前质量分数: {review_result.overall_score:.1f}/100")
        feedback_parts.append(f"审核状态: {'通过' if review_result.passed else '未通过'}")
        feedback_parts.append("")

        # 2. 维度分数
        if review_result.dimension_scores:
            feedback_parts.append("【维度评分】")
            for dim_score in review_result.dimension_scores:
                status = "✓ 通过" if dim_score.passed else "✗ 未通过"
                feedback_parts.append(
                    f"- {dim_score.dimension.value}: {dim_score.score:.1f} {status}"
                )
            feedback_parts.append("")

        # 3. 问题分析（按严重程度）
        if review_result.issues:
            feedback_parts.append("【问题分析】")

            # 高严重度
            high_issues = [i for i in review_result.issues if i.severity == SeverityLevel.high]
            if high_issues:
                feedback_parts.append(f"\n高严重度问题 ({len(high_issues)} 个):")
                for issue in high_issues[:5]:  # 限制数量
                    feedback_parts.append(f"  • {issue.description}")
                    if issue.suggestion:
                        feedback_parts.append(f"    建议: {issue.suggestion}")

            # 中严重度
            medium_issues = [i for i in review_result.issues if i.severity == SeverityLevel.medium]
            if medium_issues:
                feedback_parts.append(f"\n中严重度问题 ({len(medium_issues)} 个):")
                for issue in medium_issues[:5]:
                    feedback_parts.append(f"  • {issue.description}")

            # 低严重度
            low_issues = [i for i in review_result.issues if i.severity == SeverityLevel.low]
            if low_issues:
                feedback_parts.append(f"\n低严重度问题 ({len(low_issues)} 个):")
                for issue in low_issues[:3]:
                    feedback_parts.append(f"  • {issue.description}")

            feedback_parts.append("")

        # 4. 改进建议（按维度）
        feedback_parts.append("【改进建议】")

        dimension_suggestions = self._generate_dimension_suggestions(review_result)
        for dimension, suggestions in dimension_suggestions.items():
            if suggestions:
                feedback_parts.append(f"\n{dimension}:")
                for suggestion in suggestions:
                    feedback_parts.append(f"  - {suggestion}")

        # 5. 上下文信息
        feedback_parts.append("\n【上下文信息】")
        feedback_parts.append(f"项目: {project.name}")
        feedback_parts.append(f"集数: 第 {episode.number} 集")
        feedback_parts.append(f"已重试次数: {episode.retryCount}")

        # 6. 全局设定提醒
        if project.globalContext:
            feedback_parts.append("\n【全局设定提醒】")
            if project.globalContext.worldSetting:
                feedback_parts.append(f"世界观: {project.globalContext.worldSetting[:100]}...")

            if project.globalContext.characterProfiles:
                characters = list(project.globalContext.characterProfiles.keys())
                feedback_parts.append(f"主要角色: {', '.join(characters)}")

            if project.globalContext.styleGuide:
                feedback_parts.append(f"风格指南: {project.globalContext.styleGuide[:100]}...")

        return "\n".join(feedback_parts)

    def _generate_dimension_suggestions(
        self,
        review_result: ReviewResult
    ) -> Dict[str, List[str]]:
        """
        为各维度生成改进建议

        Args:
            review_result: 审核结果

        Returns:
            维度到建议列表的映射
        """
        suggestions = {}

        for dim_score in review_result.dimension_scores:
            dimension_name = dim_score.dimension.value
            dimension_suggestions = []

            # 根据问题类型生成建议
            for issue in dim_score.issues:
                if issue.suggestion:
                    dimension_suggestions.append(issue.suggestion)

            # 如果没有具体建议，添加通用建议
            if not dimension_suggestions and not dim_score.passed:
                dimension_suggestions.append(
                    self._get_generic_suggestion(dim_score.dimension)
                )

            if dimension_suggestions:
                suggestions[dimension_name] = dimension_suggestions[:3]  # 限制数量

        return suggestions

    def _get_generic_suggestion(self, dimension: DimensionType) -> str:
        """
        获取维度的通用改进建议

        Args:
            dimension: 维度类型

        Returns:
            通用建议文本
        """
        generic_suggestions = {
            DimensionType.consistency: "确保人物设定、场景设定、剧情逻辑与之前剧集保持一致",
            DimensionType.quality: "提升文字质量，改善表达流畅度和准确性",
            DimensionType.pacing: "调整剧情节奏，确保叙事速度适中，不急不缓",
            DimensionType.dialogue: "优化对话质量，确保人物说话风格符合其性格设定",
            DimensionType.character: "深化人物塑造，增强角色性格的立体性和可信度",
            DimensionType.plot: "完善剧情逻辑，修复剧情漏洞，增强情节合理性"
        }

        return generic_suggestions.get(
            dimension,
            "请根据具体问题进行改进"
        )

    def get_retry_history(self, episode_id: str) -> List[Dict[str, Any]]:
        """
        获取剧集的重试历史

        Args:
            episode_id: 剧集ID

        Returns:
            重试历史记录
        """
        return self.retry_history.get(episode_id, [])

    def clear_retry_history(self, episode_id: Optional[str] = None):
        """
        清除重试历史

        Args:
            episode_id: 剧集ID（可选，不提供则清除所有）
        """
        if episode_id:
            if episode_id in self.retry_history:
                del self.retry_history[episode_id]
        else:
            self.retry_history.clear()


# 全局单例
_retry_manager: Optional[RetryManager] = None


def get_retry_manager() -> RetryManager:
    """获取重试管理器单例"""
    global _retry_manager
    if _retry_manager is None:
        _retry_manager = RetryManager()
    return _retry_manager
