"""剪辑计划 / 模板 config JSON 结构定义.

定义 EditPlan.config 和 EditTemplate.config 中 cover / title / subtitle / bgm
四个子结构的 Pydantic 模型，供 API 层做入参校验和默认值填充。

所有字段均有合理默认值，前端可只传需要修改的字段。
"""

from __future__ import annotations

from enum import Enum
from typing import List, Optional

from pydantic import BaseModel, Field

# ── 枚举类型 ──────────────────────────────────────────────────────────────────


class CoverType(str, Enum):
    """封面来源类型"""

    AI_FRAME = "ai_frame"  # AI 智能选帧
    MANUAL = "manual"  # 手动选择帧
    UPLOAD = "upload"  # 用户上传
    AI_REGENERATE = "ai_regenerate"  # AI 重新生成


class TextPosition(str, Enum):
    """文字位置"""

    TOP = "top"
    CENTER = "center"
    BOTTOM = "bottom"


class TextAnimation(str, Enum):
    """文字动画效果"""

    NONE = "none"
    FADE_IN = "fade_in"
    SLIDE_UP = "slide_up"
    SLIDE_DOWN = "slide_down"
    SCALE = "scale"


class BGMSource(str, Enum):
    """BGM 来源"""

    LIBRARY = "library"  # 素材库
    UPLOAD = "upload"  # 用户上传
    AI_RECOMMEND = "ai_recommend"  # AI 推荐


# ── 子结构模型 ────────────────────────────────────────────────────────────────


class StrokeConfig(BaseModel):
    """文字描边配置"""

    enabled: bool = Field(default=False, description="是否启用描边")
    color: str = Field(default="#000000", description="描边颜色 (HEX)")
    width: int = Field(default=1, ge=1, le=10, description="描边宽度")


class ShadowConfig(BaseModel):
    """文字阴影配置"""

    enabled: bool = Field(default=False, description="是否启用阴影")
    blur: int = Field(default=4, ge=0, le=20, description="模糊半径")
    offset_x: int = Field(default=2, description="X 偏移")
    offset_y: int = Field(default=2, description="Y 偏移")


class CoverConfig(BaseModel):
    """封面配置

    type 说明:
    - ai_frame: AI 从视频中智能选取最佳帧
    - manual: 用户手动指定 frame_time 处的帧
    - upload: 用户上传图片，image_url 为上传后的地址
    - ai_regenerate: AI 重新生成封面图
    """

    type: CoverType = Field(default=CoverType.AI_FRAME, description="封面来源类型")
    image_url: str = Field(default="", description="封面图片 URL")
    frame_time: Optional[float] = Field(default=None, ge=0.0, description="截取帧时间点 (秒)")


class TitleConfig(BaseModel):
    """标题配置"""

    enabled: bool = Field(default=True, description="是否显示标题")
    ai_auto: bool = Field(default=True, description="是否由 AI 自动生成标题文案")
    text: str = Field(default="", description="标题文案 (ai_auto=false 时由用户填写)")
    position: TextPosition = Field(default=TextPosition.TOP, description="标题位置")
    font: str = Field(default="思源黑体", description="字体名称")
    color: str = Field(default="#ffffff", description="文字颜色 (HEX)")
    size: int = Field(default=48, ge=12, le=120, description="字号")
    bold: bool = Field(default=True, description="是否加粗")
    italic: bool = Field(default=False, description="是否斜体")
    stroke: StrokeConfig = Field(default_factory=StrokeConfig, description="描边配置")
    shadow: ShadowConfig = Field(default_factory=ShadowConfig, description="阴影配置")


class SubtitleConfig(BaseModel):
    """字幕配置"""

    enabled: bool = Field(default=True, description="是否显示字幕")
    position: TextPosition = Field(default=TextPosition.BOTTOM, description="字幕位置")
    font: str = Field(default="思源黑体", description="字体名称")
    color: str = Field(default="#ffffff", description="文字颜色 (HEX)")
    size: int = Field(default=24, ge=12, le=60, description="字号")
    animation: TextAnimation = Field(default=TextAnimation.FADE_IN, description="入场动画")


class BGMConfig(BaseModel):
    """BGM 配置"""

    source: BGMSource = Field(default=BGMSource.LIBRARY, description="BGM 来源")
    asset_id: str = Field(default="", description="BGM 素材 ID")
    volume: float = Field(default=0.3, ge=0.0, le=1.0, description="音量 (0.0 ~ 1.0)")


# ── 完整 config 模型 ─────────────────────────────────────────────────────────


class EditPlanConfigSchema(BaseModel):
    """EditPlan.config 完整结构

    用于 API 层校验和默认值填充。所有子结构均可选，
    未传入时使用各自默认值。
    """

    cover: CoverConfig = Field(default_factory=CoverConfig, description="封面配置")
    title: TitleConfig = Field(default_factory=TitleConfig, description="标题配置")
    subtitle: SubtitleConfig = Field(default_factory=SubtitleConfig, description="字幕配置")
    bgm: BGMConfig = Field(default_factory=BGMConfig, description="BGM 配置")


class EditTemplateConfigSchema(BaseModel):
    """EditTemplate.config 完整结构

    模板级别的默认配置，创建计划时可作为初始值继承。
    """

    cover: CoverConfig = Field(default_factory=CoverConfig, description="封面默认配置")
    title: TitleConfig = Field(default_factory=TitleConfig, description="标题默认配置")
    subtitle: SubtitleConfig = Field(default_factory=SubtitleConfig, description="字幕默认配置")
    bgm: BGMConfig = Field(default_factory=BGMConfig, description="BGM 默认配置")


# ── 默认值常量 ────────────────────────────────────────────────────────────────

DEFAULT_EDIT_PLAN_CONFIG: dict = {
    "cover": {
        "type": "ai_frame",
        "image_url": "",
        "frame_time": None,
    },
    "title": {
        "enabled": True,
        "ai_auto": True,
        "text": "",
        "position": "top",
        "font": "思源黑体",
        "color": "#ffffff",
        "size": 48,
        "bold": True,
        "italic": False,
        "stroke": {"enabled": False, "color": "#000000", "width": 1},
        "shadow": {"enabled": False, "blur": 4, "offset_x": 2, "offset_y": 2},
    },
    "subtitle": {
        "enabled": True,
        "position": "bottom",
        "font": "思源黑体",
        "color": "#ffffff",
        "size": 24,
        "animation": "fade_in",
    },
    "bgm": {
        "source": "library",
        "asset_id": "",
        "volume": 0.3,
    },
}

DEFAULT_EDIT_TEMPLATE_CONFIG: dict = DEFAULT_EDIT_PLAN_CONFIG.copy()


# ── 工具函数 ──────────────────────────────────────────────────────────────────


def normalize_plan_config(raw: dict | None) -> dict:
    """将原始 config dict 标准化，填充缺失字段为默认值。

    用于创建/更新计划时确保 config 结构完整。
    """
    if raw is None:
        return DEFAULT_EDIT_PLAN_CONFIG.copy()

    import copy

    base = copy.deepcopy(DEFAULT_EDIT_PLAN_CONFIG)

    for section_key in ("cover", "title", "subtitle", "bgm"):
        if section_key in raw and isinstance(raw[section_key], dict):
            if section_key not in base:
                base[section_key] = {}
            base[section_key].update(raw[section_key])

    # 保留非标准字段（如 generation_task_id）
    for key, value in raw.items():
        if key not in ("cover", "title", "subtitle", "bgm"):
            base[key] = value

    return base


def normalize_template_config(raw: dict | None) -> dict:
    """将模板原始 config dict 标准化。逻辑同 normalize_plan_config。"""
    return normalize_plan_config(raw)
