"""
Prompt 简单加载器
=================
从文件加载 Prompt，支持热更新。

目录结构约定：
  system/
  ├── <category>/               # 大类目录
  │   ├── <subcategory>/        # 小类目录
  │   │   ├── _meta.json        # 元数据 {"name": "显示名称"}
  │   │   ├── 1.txt             # 提示词文件（随机取其一）
  │   │   └── 2.txt
  │   └── ...
  └── ...
"""

import json
import random
from pathlib import Path
from string import Template

_PROMPTS_DIR = Path(__file__).parent


def load_prompt(path: str) -> str:
    """
    加载 Prompt 文件

    Args:
        path: 相对路径，如 "script/system", "polish/scene"

    Returns:
        Prompt 内容，文件不存在返回空字符串
    """
    file_path = _PROMPTS_DIR / f"{path}.txt"
    if file_path.exists():
        return file_path.read_text(encoding="utf-8")
    return ""


def render_template(template: str, **kwargs) -> str:
    """
    安全渲染模板变量

    Args:
        template: 模板字符串
        **kwargs: 变量值

    Returns:
        渲染后的字符串
    """
    try:
        # 转义 $ 符号防止用户输入干扰
        safe_kwargs = {k: str(v).replace("$", "$$") for k, v in kwargs.items()}
        return Template(template).substitute(**safe_kwargs)
    except KeyError as e:
        raise ValueError(f"模板缺少变量: {e}")


# ====================== 新分类体系：动态扫描 ======================

SYSTEM_PROMPTS_DIR = _PROMPTS_DIR / "system"
_SYSTEM_META_PATH = SYSTEM_PROMPTS_DIR / "_meta.json"


def _load_system_meta() -> dict:
    """读取 system/_meta.json"""
    if _SYSTEM_META_PATH.exists():
        try:
            return json.loads(_SYSTEM_META_PATH.read_text(encoding="utf-8"))
        except (json.JSONDecodeError, OSError):
            pass
    return {}


def list_categories() -> list[dict]:
    """
    返回所有分类结构

    以 system/_meta.json 为准，只返回配置中定义的大类。

    Returns:
        [
          {
            "code": "bk",
            "name": "装修避坑"
          },
          ...
        ]
    """
    meta = _load_system_meta()
    categories = []

    for cat_meta in meta.get("categories", []):
        cat_code = cat_meta["code"]
        cat_name = cat_meta.get("name", cat_code)
        categories.append({
            "code": cat_code,
            "name": cat_name,
        })

    return categories


def list_prompt_files(category: str) -> list[dict]:
    """
    扫描指定分类目录下的所有提示词文件

    文件名格式: 文案——描述.txt
    解析为 label + desc 返回给前端展示。

    Args:
        category: 大类代码，如 "bk"

    Returns:
        [
          {
            "filename": "水电改造避坑——水电改造的4个坑.txt",
            "label": "水电改造避坑",
            "desc": "水电改造的4个坑"
          },
          ...
        ]
    """
    cat_dir = SYSTEM_PROMPTS_DIR / category
    if not cat_dir.exists():
        return []

    files = []
    for f in sorted(cat_dir.iterdir()):
        if f.is_file() and f.suffix == ".txt":
            name = f.stem  # 不含 .txt
            if "——" in name:
                label, desc = name.split("——", 1)
            else:
                label = name
                desc = ""
            files.append({
                "filename": f.name,
                "label": label.strip(),
                "desc": desc.strip(),
            })

    return files


def load_prompt_file(category: str, filename: str) -> str:
    """
    加载指定分类下的指定提示词文件

    Args:
        category: 大类代码，如 "bk"
        filename: 文件名，如 "水电改造避坑——水电改造的4个坑.txt"

    Returns:
        提示词内容，文件不存在返回空字符串
    """
    file_path = SYSTEM_PROMPTS_DIR / category / filename
    if file_path.exists():
        return file_path.read_text(encoding="utf-8")
    return ""


def load_system_prompt(category: str, subcategory: str) -> str:
    """
    【已废弃】根据大类+小类随机加载一个 System Prompt

    保留兼容旧调用，实际行为改为从平铺文件中随机加载。
    """
    files = list_prompt_files(category)
    if not files:
        return ""
    chosen = random.choice(files)  # nosec: B311
    return load_prompt_file(category, chosen["filename"])



def load_script_user_prompt(
    topic: str,
    extra_params: str | None = None,
) -> str:
    """
    加载并渲染脚本生成 User Prompt

    Args:
        topic: 创作主题名称
        extra_params: 额外参数（如风格、人设等），以换行分隔的字符串

    Returns:
        渲染后的用户提示词
    """
    template = load_prompt("user/script")
    return render_template(
        template,
        topic=topic,
        extra_params=extra_params or "",
    )


class ScriptPromptBuilder:
    """
    脚本 Prompt 构建器

    用于构建家装行业短视频脚本的 System Prompt。
    """

    def build(
        self,
        duration: int = 30,
        script_type: str = "干货型",
        video_style: str = "口播",
        industry: str = "家装",
        tone: str | None = None,
        custom_requirements: str | None = None,
    ) -> str:
        """
        构建系统 Prompt

        Args:
            duration: 视频时长（秒）
            script_type: 脚本类型（干货型、故事型等）
            video_style: 视频风格（口播、剧情等）
            industry: 行业（家装）
            tone: 语气风格
            custom_requirements: 自定义要求

        Returns:
            完整的 System Prompt
        """
        # 基础 System Prompt（已废弃的脚本 system.txt，这里留空）
        base_prompt = ""

        # 构建上下文信息
        context_parts = [
            f"行业：{industry}",
            f"时长：{duration}秒",
            f"类型：{script_type}",
            f"风格：{video_style}",
        ]

        if tone:
            context_parts.append(f"语气：{tone}")

        context = "\n".join(context_parts)

        # 构建完整 Prompt
        full_prompt = f"""{base_prompt}

【创作要求】
{context}
"""

        if custom_requirements:
            full_prompt += f"""
【特殊要求】
{custom_requirements}
"""

        # 添加输出格式要求
        full_prompt += """
【输出格式】
请严格按照以下 JSON 数组格式返回，每个元素代表一个镜头：
[
  {
    "id": 1,
    "type": "segment",
    "scene": "画面描述",
    "voiceover": "配音文本",
    "duration": "5s"
  }
]

type 可以是：
- "segment": 分镜（有画面+配音）
- "empty_shot": 空镜（纯画面，voiceover 可为空）

注意：
1. 只返回 JSON 数组，不要有其他文字
2. 确保 JSON 格式正确
3. 总时长必须严格控制在要求范围内
"""

        return full_prompt


class PolishPromptBuilder:
    """
    润色 Prompt 构建器

    用于构建润色文案或画面描述的 Prompt。
    """

    POLISH_TYPES = {
        "scene": "画面描述",
        "voiceover": "配音文本",
        "text": "文案内容",
    }

    def build(self, polish_type: str = "voiceover") -> str:
        """
        构建润色 Prompt

        Args:
            polish_type: 润色类型（scene/voiceover/text）

        Returns:
            System Prompt
        """
        if polish_type == "scene":
            return self._build_scene_prompt()
        else:
            return self._build_voiceover_prompt()

    def _build_scene_prompt(self) -> str:
        """构建画面描述润色 Prompt"""
        return """你是一位专业的视频画面描述优化师。你的任务是优化画面描述，使其更加生动、具体、有画面感。

优化要求：
1. 增加细节描写（光线、色彩、构图）
2. 使用专业的影视语言
3. 描述要具体可执行
4. 保持简洁，不要过度渲染
5. 适合 AI 视频生成模型理解

请直接返回优化后的画面描述，不要添加解释。"""

    def _build_voiceover_prompt(self) -> str:
        """构建配音文本润色 Prompt"""
        return """你是一位专业的短视频文案编辑。你的任务是优化口播文案，使其更加流畅、有吸引力。

优化要求：
1. 语言口语化，适合朗读
2. 增加节奏感和停顿
3. 保留核心信息点
4. 适当使用修辞手法
5. 控制字数，不要过长

请直接返回优化后的文案，不要添加解释。"""
