"""
剧集创作 Agent 现在暂未实现

固定工作流：
1. 加载全局上下文和历史记忆
2. 结构分析
3. 大纲生成
4. 对话创作
5. 一致性审核
6. 更新记忆系统
"""
from typing import Dict, Any, Optional
from datetime import datetime
from app.models.project import SeriesProject, Episode, EpisodeIssue, TaskType
from app.core.skills.skill_manager import get_skill_manager
from app.core.skills.skill_resolver import get_skill_resolver
from app.core.llm.glm_client import get_glm_client
from app.utils.logger import get_logger
import json

logger = get_logger(__name__)


class SeriesCreationAgent:
    """
    剧集创作 Agent

    负责执行完整的剧集创作工作流
    """

    def __init__(self):
        self.skill_manager = get_skill_manager()
        self.skill_resolver = get_skill_resolver()
        self.glm_client = get_glm_client()
        logger.info("剧集创作 Agent 初始化完成")

    async def execute_episode(
        self,
        project: SeriesProject,
        episode_number: int,
        title: str = ""
    ) -> Episode:
        """
        执行单集创作
        """
        logger.info(f"开始创作 EP{episode_number}")

        # 获取现有剧集数据（如果有）
        from app.db.repositories import episode_repo
        episodes = await episode_repo.list_by_project(project.id)
        existing_episode = next((ep for ep in episodes if ep.number == episode_number), None)

        # 创建或更新 Episode 对象
        episode = Episode(
            projectId=project.id,
            number=episode_number,
            title=title or (existing_episode.title if existing_episode else f"第{episode_number}集内容创作"),
            status="writing"
        )
        if existing_episode:
            episode.id = existing_episode.id
            episode.outline = existing_episode.outline
            episode.content = existing_episode.content

        try:
            # ============================================
            # 阶段 1: 结构分析
            # ============================================
            if not episode.structure:
                logger.info(f"EP{episode_number} - 阶段 1: 结构分析")
                structure = await self._analyze_structure(project, episode_number)
                episode.structure = structure

            # ============================================
            # 阶段 2: 大纲生成
            # 如果已有大纲且非空，则跳过
            # ============================================
            if not episode.outline or len(episode.outline.strip()) < 10:
                logger.info(f"EP{episode_number} - 阶段 2: 大纲生成")
                outline = await self._generate_outline(project, episode_number, episode.structure)
                episode.outline = outline
            else:
                logger.info(f"EP{episode_number} - 使用已有大纲，跳过生成阶段")

            # ============================================
            # 阶段 3: 对话创作（核心）
            # ============================================
            logger.info(f"EP{episode_number} - 阶段 3: 对话创作")
            content = await self._write_dialogue(project, episode_number, episode.outline)
            episode.content = content

            # ============================================
            # 阶段 4: 质量分析和审核
            # ============================================
            logger.info(f"EP{episode_number} - 阶段 4: 质量分析和审核")
            review = await self._review_episode_full(project, episode_number, content)
            episode.qualityScore = review.get("score", 0)
            episode.issues = review.get("issues", [])
            episode.reviewResult = review.get("reviewResult")

            # ============================================
            # 阶段 5: 更新记忆系统
            # ============================================
            logger.info(f"EP{episode_number} - 阶段 5: 更新记忆系统")
            await self._update_memory(project, episode_number, content)

            # 完成
            episode.status = "completed"
            episode.completedAt = datetime.now()
            logger.info(f"EP{episode_number} 创作完成，质量分数: {episode.qualityScore}")

        except Exception as e:
            logger.error(f"EP{episode_number} 创作失败: {str(e)}", exc_info=True)
            episode.status = "needs-review"
            # 不将错误信息写入 content，避免错误信息被填入画布
            episode.content = episode.content or ""  # 保持现有内容或为空
            episode.issues = [
                EpisodeIssue(
                    type="execution_error",
                    description=str(e),
                    severity="high"
                )
            ]

        return episode

    async def _analyze_structure(
        self,
        project: SeriesProject,
        episode_number: int
    ) -> Dict[str, Any]:
        """分析本集结构"""
        # 使用默认的结构分析逻辑
        structure = {
            "episodeNumber": episode_number,
            "scenes": [],
            "keyEvents": []
        }
        return structure

    async def _generate_outline(
        self,
        project: SeriesProject,
        episode_number: int,
        structure: Dict[str, Any]
    ) -> str:
        """生成剧集大纲"""
        # 构建提示词
        context = self._build_context(project, episode_number)

        prompt = f"""请为《{project.name}》创作第 {episode_number} 集的大纲。

{context}

要求：
1. 大纲应包含 3-5 个场景
2. 每个场景简要描述情节
3. 字数 200-300 字
"""

        try:
            # 使用 SkillResolver 解析 Skills
            resolved_skills = await self.skill_resolver.resolve_skills_for_task(
                project=project,
                task_type=TaskType.OUTLINE,
                episode_number=episode_number
            )

            if resolved_skills:
                skill_data = resolved_skills[0]
                skill = skill_data["skill"]
                parameters = skill_data["parameters"]
                references = skill_data["references"]

                logger.info(f"EP{episode_number} 大纲生成使用 Skill: {skill.id}")

                return await self.glm_client.chat_with_skill(
                    skill_behavior=skill.behavior_guide,
                    user_input=prompt,
                    context=context,
                    temperature=parameters.get("temperature", 0.7),
                    references=references if references else None
                )

            # 回退到基本调用
            response = await self.glm_client.chat(
                messages=[
                    {"role": "system", "content": "你是剧集创作专家。"},
                    {"role": "user", "content": prompt}
                ]
            )
            return response["choices"][0]["message"]["content"]

        except Exception as e:
            logger.error(f"大纲生成失败: {str(e)}")
            return ""  # 返回空字符串，避免错误信息被当作内容

    async def _write_dialogue(
        self,
        project: SeriesProject,
        episode_number: int,
        outline: str
    ) -> str:
        """创作对话内容（核心阶段）"""
        context = self._build_context(project, episode_number)

        prompt = f"""请根据以下大纲创作第 {episode_number} 集的完整剧本：

大纲：
{outline}

{context}

要求：
1. 使用【场景】标记场景开始
2. 使用【人物】标记出场人物
3. 包含对话和动作描写
4. 保持人物性格和说话风格一致
"""

        try:
            # 使用 SkillResolver 解析 Skills
            resolved_skills = await self.skill_resolver.resolve_skills_for_task(
                project=project,
                task_type=TaskType.DIALOGUE,
                episode_number=episode_number
            )

            if not resolved_skills:
                # 回退方案
                logger.warning(f"EP{episode_number} 未找到对话创作 Skill，使用默认方案")
                response = await self.glm_client.chat(
                    messages=[
                        {"role": "system", "content": "你是专业的剧集编剧。"},
                        {"role": "user", "content": prompt}
                    ],
                    temperature=0.7
                )
                return response["choices"][0]["message"]["content"]

            # 使用第一个（最高优先级）Skill
            skill_data = resolved_skills[0]
            skill = skill_data["skill"]
            parameters = skill_data["parameters"]
            references = skill_data["references"]

            logger.info(
                f"EP{episode_number} 对话创作使用 Skill: {skill.id}, "
                f"参数: {parameters}, 参考文件数: {len(references)}"
            )

            # 使用 Skill 行为指导 + 参考文件
            return await self.glm_client.chat_with_skill(
                skill_behavior=skill.behavior_guide,
                user_input=prompt,
                context=context,
                temperature=parameters.get("temperature", 0.7),
                references=references if references else None
            )

        except Exception as e:
            logger.error(f"对话创作失败: {str(e)}")
            return ""  # 返回空字符串，避免错误信息被当作内容

    async def _review_consistency(
        self,
        project: SeriesProject,
        episode_number: int,
        content: str
    ) -> Dict[str, Any]:
        """审核一致性（保留兼容）"""
        return await self._review_episode_full(project, episode_number, content)

    async def _review_episode_full(
        self,
        project: SeriesProject,
        episode_number: int,
        content: str
    ) -> Dict[str, Any]:
        """完整剧集审核，包括多维度分析和审核卡片推送"""
        try:
            from app.core.review.review_manager import get_review_manager
            from app.models.review import ReviewConfig, DimensionConfig, DimensionType

            review_manager = get_review_manager()

            # 构建审核配置
            review_config = ReviewConfig(
                enabled_review_skills=["consistency_checker"],
                overall_strictness=0.7,
                pass_threshold=75.0
            )

            # 添加默认维度
            for dim_type in [
                DimensionType.consistency,
                DimensionType.quality,
                DimensionType.dialogue,
                DimensionType.character,
                DimensionType.plot
            ]:
                review_config.dimension_settings[dim_type] = DimensionConfig(
                    enabled=True,
                    strictness=0.7,
                    weight=1.0
                )

            # 创建 Episode 对象用于审核
            episode = Episode(
                projectId=project.id,
                number=episode_number,
                title=f"第{episode_number}集内容创作",
                status="completed",
                content=content,
                completedAt=datetime.now()
            )

            # 执行完整审核
            review_result = await review_manager.review_episode(
                project=project,
                episode=episode,
                config=review_config
            )

            # 转换为 EpisodeIssue 格式
            episode_issues = [
                EpisodeIssue(
                    type=issue.type.value,
                    description=issue.description,
                    severity=issue.severity.value,
                    suggestion=issue.suggestion
                )
                for issue in review_result.issues
            ]

            logger.info(
                f"完整审核完成: 总分={review_result.overall_score:.1f}, "
                f"通过={'是' if review_result.passed else '否'}, "
                f"问题数={len(review_result.issues)}"
            )

            # 推送审核卡片到前端（通过 WebSocket）
            await self._push_review_card(project.id, episode_number, review_result)

            return {
                "score": review_result.overall_score,
                "issues": episode_issues,
                "reviewResult": {
                    "dimensionScores": [
                        {
                            "dimension": ds.dimension.value,
                            "score": ds.score,
                            "passed": ds.passed,
                            "issueCount": ds.issue_count
                        }
                        for ds in review_result.dimension_scores
                    ],
                    "passed": review_result.passed,
                    "highSeverityCount": review_result.high_severity_count,
                    "mediumSeverityCount": review_result.medium_severity_count
                }
            }

        except Exception as e:
            logger.error(f"完整审核失败: {str(e)}")
            import traceback
            traceback.print_exc()
            return {"score": 80, "issues": [], "reviewResult": None}

    async def _push_review_card(
        self,
        project_id: str,
        episode_number: int,
        review_result: Any
    ):
        """推送审核卡片到前端"""
        try:
            from app.api.v1.websocket import broadcast_to_project

            # 构建审核卡片数据
            card_data = {
                "type": "review_card",
                "episode_number": episode_number,
                "overall_score": review_result.overall_score,
                "passed": review_result.passed,
                "issue_count": len(review_result.issues),
                "high_severity_count": review_result.high_severity_count,
                "medium_severity_count": review_result.medium_severity_count,
                "dimension_scores": [
                    {
                        "dimension": ds.dimension.value,
                        "score": ds.score,
                        "passed": ds.passed
                    }
                    for ds in review_result.dimension_scores
                ],
                "issues": [
                    {
                        "type": issue.type.value,
                        "dimension": issue.dimension.value,
                        "severity": issue.severity.value,
                        "description": issue.description,
                        "suggestion": issue.suggestion,
                        "location": {
                            "episode": issue.location.episode,
                            "scene": issue.location.scene
                        } if issue.location.scene else None
                    }
                    for issue in review_result.issues[:10]  # 最多显示10个问题
                ],
                "timestamp": datetime.now().isoformat()
            }

            # 广播到项目
            await broadcast_to_project(
                project_id=project_id,
                message_type="review_complete",
                data=card_data
            )

            logger.info(f"已推送审核卡片到项目 {project_id}, EP{episode_number}")

        except Exception as e:
            logger.error(f"推送审核卡片失败: {str(e)}")

    async def _update_memory(
        self,
        project: SeriesProject,
        episode_number: int,
        content: str
    ):
        """更新记忆系统并同步上下文到前端"""
        from app.core.memory.memory_manager import get_memory_manager

        # 创建 Episode 对象
        episode = Episode(
            projectId=project.id,
            number=episode_number,
            title=f"第{episode_number}集",
            status="completed",
            content=content,
            completedAt=datetime.now()
        )

        # 调用 MemoryManager 更新记忆
        memory_manager = get_memory_manager()
        result = await memory_manager.update_memory_from_episode(project, episode)

        logger.info(
            f"记忆更新完成: 事件={result.events_extracted}, "
            f"伏笔={result.foreshadowing_detected}, "
            f"待收线={result.threads_suggested}, "
            f"角色状态={result.character_states_updated}, "
            f"一致性问题={result.consistency_issues_found}"
        )

        # 同步上下文状态到前端（通过 WebSocket）
        await self._sync_context_states(project.id, episode_number, project.memory)

        return result

    async def _sync_context_states(
        self,
        project_id: str,
        episode_number: int,
        memory: Any
    ):
        """同步上下文状态到前端"""
        try:
            from app.api.v1.websocket import broadcast_to_project

            # 提取角色状态作为上下文状态
            context_states = []

            # 添加时间状态
            context_states.append({
                "type": "time",
                "value": f"EP{episode_number} 完成后"
            })

            # 添加角色状态
            character_states = getattr(memory, 'characterStates', {})
            if isinstance(character_states, dict):
                for char_name, states in character_states.items():
                    if states and isinstance(states, list) and len(states) > 0:
                        latest_state = states[-1]
                        if isinstance(latest_state, dict):
                            state_value = latest_state.get('state', f"{char_name}状态")
                        else:
                            state_value = getattr(latest_state, 'state', f"{char_name}状态")

                        context_states.append({
                            "type": "character",
                            "value": f"{char_name}: {state_value}",
                            "character": char_name,
                            "state": state_value
                        })

            # 添加待收线数量
            pending_threads = getattr(memory, 'pendingThreads', [])
            if pending_threads:
                context_states.append({
                    "type": "pending_threads",
                    "value": f"待收线: {len(pending_threads)} 条"
                })

            # 广播上下文更新
            await broadcast_to_project(
                project_id=project_id,
                message_type="context_update",
                data={
                    "states": context_states,
                    "episode_number": episode_number
                }
            )

            logger.info(f"已同步上下文状态到项目 {project_id}, {len(context_states)} 个状态")

        except Exception as e:
            logger.error(f"同步上下文状态失败: {str(e)}")

    def _build_context(
        self,
        project: SeriesProject,
        episode_number: int
    ) -> str:
        """构建上下文字符串"""
        context_parts = []

        # 1. 世界观 (防御性检查)
        world_setting = getattr(project.globalContext, 'worldSetting', '')
        if world_setting:
            context_parts.append(f"世界观：{world_setting}")

        # 2. 人物设定 (防御性检查)
        profiles = getattr(project.globalContext, 'characterProfiles', {})
        if isinstance(profiles, dict) and profiles:
            context_parts.append("\n人物设定：")
            for char_id, char in profiles.items():
                name = getattr(char, 'name', '未知角色')
                personality = getattr(char, 'personality', '')
                speech_style = getattr(char, 'speechStyle', '')
                context_parts.append(f"- {name}：{personality}，说话风格：{speech_style}")
        elif isinstance(profiles, str) and profiles:
            # 兼容字符串格式
            context_parts.append(f"\n人物设定：\n{profiles}")

        # 3. 风格指南
        style_guide = getattr(project.globalContext, 'styleGuide', '')
        if style_guide:
            context_parts.append(f"\n创作风格指南：\n{style_guide}")

        # 4. 历史记忆 (最近3集)
        memory_timeline = getattr(project.memory, 'eventTimeline', [])
        if isinstance(memory_timeline, list) and memory_timeline:
            context_parts.append("\n历史剧情：")
            recent_events = memory_timeline[-3:]
            for event in recent_events:
                if isinstance(event, dict):
                    context_parts.append(f"- {event.get('event', '')}")
                else:
                    context_parts.append(f"- {str(event)}")

        return "\n".join(context_parts)


# 全局单例
_agent_instance: Optional[SeriesCreationAgent] = None


def get_series_agent() -> SeriesCreationAgent:
    """获取剧集创作 Agent 单例"""
    global _agent_instance
    if _agent_instance is None:
        _agent_instance = SeriesCreationAgent()
    return _agent_instance
