#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
结构化内容库Agent（视频分析版本）

功能:
1. 从 state 中读取视频文件对象
2. 使用 Gemini 视频分析能力，直接基于视频内容进行结构化解构
3. 输出严格符合约定结构的 JSON 数据，用于内容库建设
"""

from typing import Any, Dict, List

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 StructureAgent(BaseLLMAgent):
    """结构化内容库Agent - 基于视频分析的显性事实解构"""

    def __init__(
        self,
        name: str = "structure_agent",
        description: str = "结构化内容库Agent - 基于视频内容显性事实进行解构",
        model_provider: str = "google_genai",
        temperature: float = 0.2,
        max_tokens: int = 20480,
    ):
        # 这里的 system_prompt 仅用于初始化模型（提供 model_name），
        # 实际的视频分析逻辑全部通过 safe_invoke_video_analysis 的 prompt 控制
        system_prompt = "你是一名专注于中国60岁以上老年群体内容分析的结构化解构专家。"
        super().__init__(
            name=name,
            description=description,
            model_provider=model_provider,
            system_prompt=system_prompt,
            temperature=temperature,
            max_tokens=max_tokens,
        )

    # ==================== 对外主入口 ====================

    def process(self, state: Dict[str, Any], config=None) -> Dict[str, Any]:
        """处理状态：读取视频 → 调用视频分析 → 写回结构化结果

        步骤：
        1. 从 state 中读取视频文件对象
        2. 直接调用 safe_invoke_video_analysis，基于视频内容做结构化解构
        3. 将结构化结果写回 state

        Returns:
            dict: {"structure_data": <LLM解析后的JSON>}
        """
        if not self.is_initialized:
            self.initialize()

        logger.info("StructureAgent 开始执行")

        # Step 0: 从 state 中获取视频文件对象
        video_file = get_video_file_from_state(state)
        if not video_file:
            logger.warning("无法获取视频文件对象，跳过结构化解构分析")
            return {
                "structure_data": {
                    "错误": "无法获取视频文件对象",
                },
            }

        try:
            # 直接基于视频内容进行结构化解构分析
            logger.info("基于视频内容进行结构化解构分析...")
            prompt = self._build_prompt()

            result = LLMInvoker.safe_invoke_video_analysis(
                "结构化内容库解构",
                video_file,
                prompt,
                agent=self,
                fallback=self._build_empty_result(),
            )

            logger.info("StructureAgent 执行完成")

            # 统一写回到 state 的字段名
            return {"structure_data": result}

        except Exception as e:
            logger.error(f"StructureAgent 执行失败: {e}", exc_info=True)
            return {
                "structure_data": {
                    "错误": str(e),
                }
            }

    # ==================== Prompt 构建 ====================

    def _build_prompt(self) -> str:
        """构建基于视频内容的结构化解构 Prompt"""
        return """
# 角色设定
你是一名专注于中国60岁以上老年群体的内容分析专家。你的核心能力是从视频内容中基于"显性事实"精准提炼信息，构建结构化的内容库数据。

# 任务目标
请仔细观看我提供的【视频内容】，进行深度解构，并输出一个严格符合要求的 JSON 格式数据。

# 关键约束
1. **只能根据视频中的画面、解说、环境音、人物对话来分析内容**。
2. **禁止**把画面上的任何文字内容（如字幕、贴片文案、标题、弹幕、备注说明等）作为主要依据。如果画面中出现文字，只能通过**描述该画面的含义或功能**来理解，而不是逐字记录文字内容。
3. 必须基于视频的实际内容进行分析，不能凭空臆造。

# 核心原则
1. 显性事实原则：只解构视频中明确出现过的人、事、物、观点。绝对禁止基于经验进行主观推测（例如：视频未提"老年人"，不可强行打上"老年人"标签）。
2. 全中文原则：输出结果中的所有字段名（Key）和内容值（Value）必须全部使用简体中文，不得出现任何英语单词。
3. 格式规范原则：输出纯净的 JSON 格式，不要包含 Markdown 代码块标记（```json），也不要包含任何解释性文字。

# 解构维度说明
你需要将信息解构为以下三个核心表：
## 1. 选题信息表
目的：提炼视频的核心事实命题。
- 宏观母题：用一句话概括视频整体内容的完整命题（格式：主语 + 核心事件/结论）。
- 高潜子题列表：
  - 逻辑：仅当视频为"盘点/合集/并列结构"时（如"12个村庄"、"4个养生妙招"），提取其中具备独立爆款潜力的具体条目。
  - 注意：如果视频为"线性/单体/情感叙事"（如"怀念周总理"、"老同学情谊"），此项请输出空数组 []，严禁强行拆解。
## 2. 模型信息表
目的：提取逻辑公式，用于横向扩展匹配同构内容。
- 抽象逻辑模型列表：将具体的人/事/物抽象为变量，形成逻辑公式。
  - 格式示例："[对象:伟人] + [反常细节:补丁衣服] + [精神:艰苦朴素]"
  - 要求：提取视频中最核心的 1-2 个逻辑模型。
## 3. 层级标签树
目的：提取实体层级，用于精准搜索与纵向升维。
- L1_实例名词：视频中无可辩驳的、最具体的专有名词（人名、地名、物名）。
- L1_限定词：关键！视频中明确出现的、限定了受众身份或时间状态的词（如：晚年、白头、退休、1978年、农村、老祖宗）。如果没有则留空。
- L2_具体品类：L1 的直接父级分类。必须精准（例如：是"晚年社交"而不是"社交"，是"红色地标"而不是"景点"）。
- L3_兴趣领域：注意！必须使用"用户兴趣/情绪分类"，严禁使用"历史、地理、生物"等学术分类。
  - 正确示例：红色记忆、奇闻异事、大国工程、中医智慧、怀旧岁月、玄学民俗。
  - 错误示例：历史、旅游、建筑、医学、生物。
- L4_情绪价值：内容背后的情绪钩子或社会价值。仅在有明显的升维价值时提取（如：民族自信、致青春、趋吉避凶、鞠躬尽瘁），否则留空。

# 参考案例 (Few-Shot)
## 案例一：线性叙事/红色题材
**输入视频内容**: "您走了48年...这里是周恩来纪念馆...12岁立志为中华之崛起而读书...75岁体重只有61斤...开国大典飞机飞两趟..."
**输出 JSON**:
{
  "选题信息表": {
    "宏观母题": "走进淮安周恩来纪念馆回顾总理鞠躬尽瘁的一生",
    "高潜子题列表": []
  },
  "模型信息表": {
    "抽象逻辑模型列表": [
      "[对象:伟人/元勋] + [高龄/病重] + [反常细节:体重过轻/补丁] + [精神:鞠躬尽瘁]",
      "[历史节点:开国大典] + [遗憾:飞机不够] + [如今:盛世] + [情感:如您所愿]"
    ]
  },
  "层级标签树": {
    "L1_实例名词": ["周恩来", "淮安", "开国大典"],
    "L1_限定词": ["75岁", "48年", "晚年"],
    "L2_具体品类": ["开国元勋", "红色地标"],
    "L3_兴趣领域": ["红色记忆", "党史"],
    "L4_情绪价值": ["鞠躬尽瘁", "盛世如愿", "爱国主义"]
  }
}

## 案例二：盘点结构/猎奇题材
**输入视频内容**: "中国最奇怪的12个村庄...一，云南克木人男人住树上...十二，四川俄亚大村保留一妻多夫习俗..."
**输出 JSON**:
{
  "选题信息表": {
    "宏观母题": "盘点中国最奇怪的12个村庄与部落",
    "高潜子题列表": [
      "云南克木人男人一辈子生活在树上不用干活",
      "四川俄亚大村保留一妻多夫习俗且家务由丈夫平摊",
      "贵州芭莎苗寨是中国唯一合法持枪的部落"
    ]
  },
  "模型信息表": {
    "抽象逻辑模型列表": [
      "[动作:盘点] + [范围:中国] + [定性:奇怪/原始] + [实体:村庄/部落]",
      "[地点/民族] + [保留习俗] + [核心点:一妻多夫/走婚] + [反常识家庭地位]"
    ]
  },
  "层级标签树": {
    "L1_实例名词": ["俄亚大村", "克木人", "芭莎苗寨"],
    "L1_限定词": ["原始", "古老"],
    "L2_具体品类": ["隐世部落", "奇特风俗"],
    "L3_兴趣领域": ["奇闻异事", "世界未解之谜"],
    "L4_情绪价值": ["猎奇", "颠覆认知"]
  }
}

## 案例三：情感叙事/限定词应用
**输入视频内容**: "人到晚年，最想念老同学...同窗三两载，却是悠悠一生情...头发白了..."
**输出 JSON**:
{
  "选题信息表": {
    "宏观母题": "人到晚年最想念老同学且认为同学情是一世情",
    "高潜子题列表": []
  },
  "模型信息表": {
    "抽象逻辑模型列表": [
      "[时间:晚年/余生] + [对象:老同学/老战友] + [情感:想念/聚会/重逢]"
    ]
  },
  "层级标签树": {
    "L1_实例名词": ["老同学"],
    "L1_限定词": ["晚年", "白了头", "悠悠一生"],
    "L2_具体品类": ["晚年社交", "夕阳红情谊"],
    "L3_兴趣领域": ["怀旧岁月", "情感感悟"],
    "L4_情绪价值": ["致青春", "友谊长存"]
  }
}

注意：
- 所有字段名和值必须使用简体中文。
- 严格遵守"显性事实原则"，不要凭空添加视频中不存在的信息。
- 如果某个字段在视频中完全找不到依据，可以留空字符串 "" 或空数组 []。
        """.strip()

    @staticmethod
    def _build_empty_result() -> Dict[str, Any]:
        """构建一个结构完整但内容为空的降级结果"""
        return {
            "选题信息表": {
                "宏观母题": "",
                "高潜子题列表": [],
            },
            "模型信息表": {
                "抽象逻辑模型列表": [],
            },
            "层级标签树": {
                "L1_实例名词": [],
                "L1_限定词": [],
                "L2_具体品类": [],
                "L3_兴趣领域": [],
                "L4_情绪价值": [],
            },
        }

    # ==================== BaseLLMAgent 抽象方法占位实现 ====================

    def _build_messages(self, state: Dict[str, Any]) -> List[Dict[str, Any]]:
        """满足 BaseLLMAgent 抽象要求（本 Agent 不通过该通用路径调用）"""
        return []

    def _update_state(self, state: Dict[str, Any], response: Any) -> Dict[str, Any]:
        """满足 BaseLLMAgent 抽象要求（本 Agent 不通过该通用路径调用）"""
        return state

# 这个agent用于提炼视频信息，构建结构化的内容数据库