#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
内容整体结构理解 Agent（基于视频 + L3 单元解构）

功能：
- 读取原始视频文件（Gemini File）
- 使用 L3 单元解构结果（来自 ContentUnitSplitAgent 或其他步骤）
- 调用视频模型，根据统一的 Prompt，生成：
  - L1 整体结构（Whole）
  - L2 段落结构（Paragraphs）
  - 保留 L3 单元解构（Units）
"""

import json
from typing import Any, Dict

from src.components.agents.base import BaseLLMAgent
from src.utils.logger import get_logger
from src.utils.llm_invoker import LLMInvoker, get_video_file_from_state

logger = get_logger(__name__)


class ContentUnitUnderstandAgent(BaseLLMAgent):
    """内容整体结构理解 Agent

    输入（当前版本不再依赖脚本文本，只使用「视频 + L3 解构 JSON」）：
        state: {
            # 必需：视频信息（与视频工作流保持一致）
            #   - video_file / video_file_name / video_uploaded_uri: Gemini 视频文件信息
            #
            # 必需：L3 单元解构资料（例如来自 ContentUnitSplitAgent 的输出）
            #   - content_unit_analysis: {
            #         "单元列表": [...],
            #         ...
            #     }
        }

    输出（JSON 结构，全部中文 key，便于后续解析）：
        {
            "content_unit_understanding": {
                "整体解构": {...},    # L1 层整体结构信息
                "段落解构": [...],    # L2 段落级结构列表
                "单元解构": {...}     # 可选：直接附上 L3 解构的摘要或引用
            }
        }
    """

    def __init__(
        self,
        name: str = "content_unit_understand_agent",
        description: str = "内容整体结构理解Agent - 基于视频与L3单元资料，归纳L2段落与L1整体结构",
        model_provider: str = "google_genai",
        temperature: float = 0.3,
        max_tokens: int = 40960,
    ):
        system_prompt = self._build_system_prompt()
        super().__init__(
            name=name,
            description=description,
            model_provider=model_provider,
            system_prompt=system_prompt,
            temperature=temperature,
            max_tokens=max_tokens,
        )

    def _build_system_prompt(self) -> str:
        """构建系统提示词（角色与总体要求）"""
        return (
            "你是一名世界级的内容架构师，擅长从微观单元出发，归纳视频的整体叙事结构。"
            "你需要在保证逻辑严谨与结构清晰的前提下，输出可直接阅读的中文 Markdown 报告。"
        )

    # 注意：虽然本 Agent 在自定义的 process 中直接调用了视频分析工具，
    # 但由于继承自 BaseLLMAgent（其定义了抽象方法），这里仍需提供占位实现，
    # 以避免被视为抽象类无法实例化。

    def _build_messages(self, state: Dict[str, Any]) -> Any:
        """占位实现：本 Agent 不使用 BaseLLMAgent 默认的 LLM 调用路径。"""
        return []

    def _update_state(self, state: Dict[str, Any], response: Any) -> Dict[str, Any]:
        """占位实现：实际状态更新逻辑在自定义 process 中完成。"""
        return state

    def process(self, state: Dict[str, Any], config=None) -> Dict[str, Any]:
        """处理状态 - 基于视频 + L3 单元资料进行整体结构归纳分析"""
        if not self.is_initialized:
            self.initialize()

        logger.info("=" * 80)
        logger.info("内容整体结构理解 (ContentUnitUnderstandAgent)")
        logger.info("=" * 80)

        try:
            # 1. 获取视频文件对象
            video_file = get_video_file_from_state(state)
            if not video_file:
                logger.warning("无法获取视频文件对象，跳过整体结构理解分析")
                return {
                    "content_unit_understanding": {
                        "error": "无法获取视频文件对象",
                        "markdown_result": "",
                        "raw_response": "",
                    }
                }

            # 2. 获取 L3 单元解构资料
            content_unit_analysis = state.get("content_unit_analysis", {}) or {}

            if not content_unit_analysis:
                logger.warning("缺少 L3 单元解构资料（content_unit_analysis.单元列表 为空）")

            # 3. 构建分析 Prompt（仅依赖 L3 解构和视频内容）
            prompt = self._build_analysis_prompt(content_unit_analysis=content_unit_analysis)

            logger.info("开始视频整体结构理解分析（调用 safe_invoke_video_analysis）...")

            # 5. 调用通用视频分析接口
            result = LLMInvoker.safe_invoke_video_analysis(
                operation_name="内容整体结构理解分析",
                video_file=video_file,
                prompt=prompt,
                agent=self,
                fallback={
                    "error": "视频整体结构分析返回空结果",
                },
            )

            # 6. 处理返回结果（safe_invoke_video_analysis 返回的是解析后的 JSON 对象）
            if not isinstance(result, dict) or not result:
                logger.warning("视频整体结构分析返回结果为空或非字典")
                return {
                    "content_unit_understanding": {
                        "error": "视频整体结构分析返回空结果或解析失败",
                    }
                }

            # 检查是否是错误返回（fallback）
            if "error" in result and result.get("error"):
                logger.warning(f"视频整体结构分析返回错误: {result.get('error')}")
                return {
                    "content_unit_understanding": {
                        "error": result.get("error"),
                    }
                }

            # 返回解析后的 JSON 对象（包含"整体解构"、"段落解构"、"单元解构"等中文 key）
            logger.info(f"整体结构分析完成，结果包含字段: {list(result.keys())}")
            logger.info("=" * 80)

            return {
                "content_unit_understanding": result
            }

        except Exception as e:
            logger.error(f"内容整体结构理解分析失败: {e}", exc_info=True)
            return {
                "content_unit_understanding": {
                    "error": str(e),
                    "markdown_result": "",
                    "raw_response": "",
                }
            }

    def _build_analysis_prompt(self, content_unit_analysis: Dict[str, Any]) -> str:
        """构建用于视频分析的完整 Prompt，将 L3 资料填入占位符"""

        # 将字典转换为 JSON 字符串，如果为空则使用默认提示
        if content_unit_analysis:
            l3_content = json.dumps(content_unit_analysis, ensure_ascii=False, indent=2)
        else:
            l3_content = '（当前缺少 L3 解构资料，请仅基于视频内容进行合理推断）'

        l3_block = (
            "【L3 解构资料】（来自内容单元拆分结果）：\n\n"
            f"{l3_content}\n"
        )

        logger.info(f"L3 解构资料长度: {len(l3_content)}")

        return f"""# Role
你是一名世界级的内容架构师。你拥有极强的归纳总结能力和宏观叙事分析能力。
# Context
我将给你一份材料：
1. **L3 单元解构资料**：对该脚本进行的微观拆解数据。

以下是具体内容（如果某部分为空，请忽略该部分，优先结合“视频实际内容 + 现有文字资料”进行分析，这里的文字资料仅指 L3 解构文本）： 

{l3_block}

# Task

请结合上述材料和你直接“观看视频”获得的理解，自下而上地归纳出该视频的 **L2 段落（Paragraphs）** 和 **L1 整体（Whole）** 结构，并最终整合成一份完整的解构报告。

# Logic
1.  **L2 段落 (Paragraphs)**：将相邻的、服务于同一个叙事功能的 L3 单元聚合。
    - 需要明确该段落包含哪些 L3 单元。
    - 需要对该段落的“实质（三层）× 形式（三维）”进行聚合总结。

2.  **L1 整体 (Whole)**：对整个视频的叙事脉络进行宏观定义。
    - 重点分析“纵向逻辑流”：包含整体叙事脉络（阶段划分）和节点衔接机制（段落间如何过渡）。

# Output Format (JSON)
请最终只输出一个 JSON 对象，**全部使用中文 key**，结构示例如下（可根据实际需要增减字段，但需保持语义清晰、便于解析）：

{{
  "整体解构": {{
    "节点基础信息": "整体节点信息",
    "整体实质×形式": "整体实质×形式分析",
    "纵向逻辑流": [
        {{
            "阶段编号": "阶段编号",
            "阶段逻辑名称": "阶段逻辑名称",
            "阶段逻辑描述": "阶段逻辑描述",
        }}
    ]
  }},
  "段落解构": [
    {{
      "段落序号": "段落序号",
      "时间范围": "段落时间范围",
      "包含单元": "段落包含的单元列表",
      "段落完整文案": "段落完整文案",
      "具体元素实质和形式": [
        {{
            "具体元素名称": "具体元素名称",
            "对应形式-文案": "文案形式",
            "对应形式-画面": "画面形式",
            "对应形式-声音": "声音形式"
        }}
      ],
      "具象概念实质和形式": [
        {{
            "具象概念名称": "具象概念名称",
            "对应形式-文案": "文案形式",
            "对应形式-画面": "画面形式",
            "对应形式-声音": "声音形式"
        }}
      ],
      "抽象概念实质和形式": [
        {{
            "抽象概念名称": "抽象概念名称",
            "对应形式-文案": "文案形式",
            "对应形式-画面": "画面形式",
            "对应形式-声音": "声音形式"
        }}
      ],
    }}
  ]
}}"""



