#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
搜索关键词Agent

功能: 基于视频分析结果（灵感点、目的点、关键点、选题理解）生成抖音/TikTok组合搜索词列表
核心任务: 分析视频核心构成，输出用于检索竞品内容的搜索词组合
特征: 使用"元素+语境"组合法，生成精准搜索词
"""

from typing import Any, Dict, List
import json
import re

from src.components.agents.base import BaseLLMAgent
from src.utils.logger import get_logger

logger = get_logger(__name__)


class SearchKeywordAgent(BaseLLMAgent):
    """搜索关键词Agent - 生成抖音/TikTok组合搜索词列表"""

    def __init__(
        self,
        name: str = "search_keyword_agent",
        description: str = "搜索关键词Agent - 生成组合搜索词列表",
        model_provider: str = "google_genai",
        temperature: float = 0.7,
        max_tokens: int = 8192
    ):
        """
        初始化搜索关键词Agent

        Args:
            name: Agent名称
            description: Agent描述
            model_provider: 模型提供商 ("openai" 或 "google_genai")
            temperature: 生成温度，控制创造性
            max_tokens: 最大token数
        """
        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 """# Role
你是一位精通全网内容分发逻辑与搜索引擎优化（SEO）的数据分析师。

# Task
我将提供一段关于视频内容的详细结构化数据（JSON格式），包含【灵感点】、【目的点】和【关键点】。
你的任务是分析该视频的核心构成，并输出一份**抖音/TikTok组合搜索词列表**，用于检索与该视频**题材相同、切入点相似、受众重合**的竞品内容。

# Core Strategy: "元素+语境" 组合法
为了保证搜索结果的精准度，请严格遵循 **`[核心实体/具象元素]` + `[主题语境/内容属性]`** 的组合公式进行输出。

### 1. 定义"核心实体" (Left Side)
请从 JSON 的 `关键点 (Key Points)` 和 `视频信息` 中提取最具体的名词。
* **包括**：具体的人名/地名/产品名、特定的时间节点、核心物体、显性的视觉符号、特定的动作名称。
* **排除**：泛泛的大类词（如"生活"、"快乐"、"健康"）。

### 2. 定义"主题语境" (Right Side)
请从 JSON 的 `灵感点 (Inspiration)` 和 `目的点 (Purpose)` 中提取修饰性的词汇。
* **包括**：内容的体裁（教程/测评/Vlog）、情感色彩（治愈/吐槽/焦虑）、功能属性（避坑/省钱/变美）、特定的叙事逻辑（反转/揭秘/老话）。

# Execution Rules (执行规则)
请扫描 JSON 数据，针对不同维度生成搜索词：

1.  **提取"强钩子"组合**：
    * 找到视频开头最吸引人的视觉或概念元素（灵感点）。
    * *通用公式*：`[核心视觉/事件]` + `[钩子属性(如:真相/后续/反常)]`
2.  **提取"核心内容"组合**：
    * 找到视频主要传达的知识、剧情或展示物（关键点）。
    * *通用公式*：`[具体事物/动作]` + `[垂直领域词(如:做法/技巧/评价)]`
3.  **提取"受众痛点"组合**：
    * 找到视频想要解决的问题或满足的需求（目的点）。
    * *通用公式*：`[受众标签/场景]` + `[痛点/解决方案]`

# Output Format
请输出 10-12 个组合搜索词，按以下格式排列，并简要解释组合逻辑：
* **`关键词` + `语境词`** (例如：*空气炸锅 翻车* / *重阳节 禁忌* / *面试 自我介绍*)
    * *逻辑：提取了[X]元素，结合[Y]主题。*

输出格式为JSON：
```json
{
  "搜索词列表": [
    {
      "搜索词": "关键词 语境词",
      "组合逻辑": "提取了[X]元素，结合[Y]主题。"
    }
  ]
}
```"""

    def _build_messages(self, state: Dict[str, Any]) -> List[Dict[str, Any]]:
        """
        构建LLM消息

        Args:
            state: 包含视频和其他agent结果的状态字典,需要包含:
                - inspiration_points: 灵感点提取结果
                - purpose_point: 目的点提取结果
                - key_points: 关键点提取结果
                - topic_selection_understanding: 选题理解结果

        Returns:
            消息列表
        """
        # 提取输入数据
        inspiration_points = state.get("inspiration_points", [])
        purpose_point = state.get("purpose_point", {})
        key_points = state.get("key_points", {})
        topic_selection_understanding = state.get("topic_selection_understanding", {})

        # 构建提示词
        prompt = self._build_user_prompt(
            inspiration_points,
            purpose_point,
            key_points,
            topic_selection_understanding
        )

        # 构建消息
        return [
            {"role": "system", "content": self.system_prompt},
            {"role": "user", "content": prompt}
        ]

    def _update_state(self, state: Dict[str, Any], response: Any) -> Dict[str, Any]:
        """
        更新状态

        Args:
            state: 原始状态
            response: LLM响应

        Returns:
            更新后的状态
        """
        # 解析响应
        result = self._parse_response(response.content)

        return {
            "search_keywords": result
        }

    def _build_user_prompt(
        self,
        inspiration_points: Any,
        purpose_point: Dict[str, Any],
        key_points: Dict[str, Any],
        topic_selection_understanding: Dict[str, Any]
    ) -> str:
        """构建用户提示 - 提供数据和执行指令"""
        # 格式化各维度数据
        inspiration_section = self._format_inspiration_points(inspiration_points)
        purpose_section = self._format_purpose_point(purpose_point)
        key_points_section = self._format_key_points(key_points)
        topic_section = self._format_topic_selection_understanding(topic_selection_understanding)

        return f"""# Input Data

## 选题理解结果
{topic_section}

## 灵感点分析
{inspiration_section}

## 目的点分析
{purpose_section}

## 关键点分析
{key_points_section}

---

# 执行指令

基于以上数据，输出 10-12 个组合搜索词。

## 质量要求
- **搜索词数量**: 10-12 个
- **组合公式**: `[核心实体/具象元素]` + `[主题语境/内容属性]`
- **覆盖维度**: 需要覆盖"强钩子"、"核心内容"、"受众痛点"三个维度
- **精准度**: 搜索词应该能够检索到与该视频题材相同、切入点相似、受众重合的竞品内容
- **组合逻辑**: 每个搜索词需要简要说明提取了哪些元素，结合了哪些主题

**重要提醒**：
- 核心实体必须具体，避免泛泛的大类词
- 主题语境要能体现内容的体裁、情感、功能或叙事逻辑
- 搜索词不能出现雷同和近似的词语
- 搜索词应该符合抖音/TikTok用户的搜索习惯"""

    def _format_topic_selection_understanding(self, topic_selection_understanding: Dict[str, Any]) -> str:
        """格式化选题理解信息"""
        if not topic_selection_understanding:
            return "**未找到选题理解结果**"

        主题 = topic_selection_understanding.get("主题", "")
        描述 = topic_selection_understanding.get("描述", "")

        formatted = ""
        if 主题:
            formatted += f"**主题**: {主题}\n"
        if 描述:
            formatted += f"**描述**: {描述}\n"

        return formatted if formatted else "**未找到选题理解结果**"

    def _format_inspiration_points(self, inspiration_points: Any) -> str:
        """格式化灵感点信息"""
        # 新结构：inspiration_points 直接是列表
        if isinstance(inspiration_points, list):
            if not inspiration_points:
                return "**未提取到灵感点**"

            formatted = f"**灵感点总数**: {len(inspiration_points)}\n\n"

            for idx, point in enumerate(inspiration_points, 1):
                formatted += f"### 灵感点 {idx}: {point.get('灵感点', 'N/A')}\n"
                formatted += f"**分类**: {point.get('分类', '')}\n"
                formatted += f"**描述**: {point.get('描述', '')}\n"
                if point.get("推理"):
                    formatted += f"**推理**: {point.get('推理', '')}\n"
                formatted += "\n"

            return formatted

        # 旧结构：{"points": [...]} 或字典格式
        if isinstance(inspiration_points, dict):
            # 旧结构：points列表
            if "points" in inspiration_points:
                points = inspiration_points.get("points", [])
                if not points:
                    return "**未提取到灵感点**"

                formatted = f"**灵感点总数**: {len(points)}\n\n"

                for idx, point in enumerate(points, 1):
                    formatted += f"### 灵感点 {idx}: {point.get('灵感点表象', 'N/A')}\n"
                    formatted += f"**本质**: {point.get('灵感点本质', '')}\n"
                    formatted += f"{point.get('本质详细说明', '')}\n\n"

                return formatted

        return "**未提取到灵感点**"

    def _format_purpose_point(self, purpose_point: Dict[str, Any]) -> str:
        """格式化目的点信息"""
        if not purpose_point:
            return "**未提取到目的点**"

        # 新结构：{"perspective": "创作者视角", "purposes": [...], "total_count": 2}
        purposes = purpose_point.get("purposes", [])
        if not purposes:
            return "**未提取到目的点**"

        formatted = f"**目的点总数**: {len(purposes)}\n\n"

        for idx, purpose in enumerate(purposes, 1):
            维度 = purpose.get("维度", {})
            if isinstance(维度, dict):
                维度_str = f"{维度.get('一级分类', '')}/{维度.get('二级分类', '')}"
            else:
                维度_str = str(维度)

            目的点 = purpose.get("目的点", "N/A")
            描述 = purpose.get("描述", "")

            formatted += f"### 目的点 {idx}: {目的点}\n"
            formatted += f"**维度**: {维度_str}\n"
            if 描述:
                formatted += f"**描述**: {描述}\n"
            formatted += "\n"

        return formatted

    def _format_key_points(self, key_points: Dict[str, Any]) -> str:
        """格式化关键点信息 - 支持层级结构"""
        if not key_points or "key_points" not in key_points:
            return "**未提取到关键点**"

        points = key_points.get("key_points", [])
        if not points:
            return "**未提取到关键点**"

        total_count = key_points.get("total_count", len(points))
        root_count = key_points.get("root_count", len(points))
        hierarchy_enabled = key_points.get("hierarchy_enabled", False)

        formatted = f"**关键点总数**: {total_count}\n"
        if hierarchy_enabled:
            formatted += f"**一级关键点数**: {root_count}\n"
            formatted += f"**层级结构**: 已启用\n\n"
        else:
            formatted += "\n"

        # 递归格式化关键点树
        def format_point_tree(point: Dict[str, Any], level: int = 1, index: int = 1) -> str:
            indent = "  " * (level - 1)
            result = f"{indent}### 关键点 {index} (层级 {level}): {point.get('关键点', 'N/A')}\n"
            result += f"{indent}**维度**: [{point.get('维度大类', '')}] {point.get('维度细分', '')}\n"
            result += f"{indent}**描述**: {point.get('描述', '')}\n"

            # 递归处理子关键点
            children = point.get("children", [])
            if children:
                result += f"{indent}**子关键点**: {len(children)}个\n\n"
                for child_idx, child in enumerate(children, 1):
                    result += format_point_tree(child, level + 1, child_idx)
            else:
                result += "\n"

            return result

        # 格式化所有一级关键点
        for idx, point in enumerate(points, 1):
            formatted += format_point_tree(point, level=1, index=idx)

        return formatted

    def _parse_response(self, response: str) -> Dict[str, Any]:
        """解析LLM响应"""
        try:
            # 尝试提取JSON代码块
            json_match = re.search(r'```(?:json)?\s*(.*?)\s*```', response, re.DOTALL)
            if json_match:
                json_str = json_match.group(1)
            else:
                json_str = response

            # 解析JSON
            result = json.loads(json_str)

            # 确保包含必需字段
            if "搜索词列表" not in result:
                result["搜索词列表"] = []

            # 验证每个搜索词的结构
            search_keywords = result.get("搜索词列表", [])
            validated_keywords = []
            for keyword in search_keywords:
                if isinstance(keyword, dict):
                    # 确保包含必需字段
                    validated_keyword = {
                        "搜索词": keyword.get("搜索词", ""),
                        "组合逻辑": keyword.get("组合逻辑", "")
                    }
                    if validated_keyword["搜索词"]:  # 只保留有效的搜索词
                        validated_keywords.append(validated_keyword)

            result["搜索词列表"] = validated_keywords
            result["总数"] = len(validated_keywords)

            return result

        except json.JSONDecodeError as e:
            logger.error(f"JSON解析失败: {e}")
            logger.error(f"响应内容: {response[:500]}")
            # JSON解析失败，返回默认结构
            return {
                "搜索词列表": [],
                "总数": 0,
                "错误": "解析失败"
            }
        except Exception as e:
            logger.error(f"解析响应时发生错误: {e}", exc_info=True)
            return {
                "搜索词列表": [],
                "总数": 0,
                "错误": str(e)
            }
