"""单集分析业务逻辑：摘要、资产提取、分镜拆分。"""
import logging
import uuid
from typing import Any, Optional

from pydantic import TypeAdapter
from src.models.schemas import (
    CharacterAsset,
    SceneAsset,
    PropAsset,
    Storyboard,
    ProjectData,
)
from src.services.project_service import project_manager
from src.services.script import script_service
from src.services.project_helpers import get_cinematic_defaults

logger = logging.getLogger(__name__)


async def analyze_episode(project_id: str, episode_id: str, user_id: Optional[str] = None) -> ProjectData:
    """
    分析指定集：提取摘要、角色/场景/道具、分镜，并写回项目。
    返回更新后的项目。

    Args:
        user_id: User ID for retrieving user's API key (纯用户密钥模式)
    """
    project = project_manager.get_project(project_id)
    if not project:
        raise ValueError("Project not found")
    episode = next((ep for ep in project.episodes if ep.id == episode_id), None)
    if not episode:
        raise ValueError("Episode not found")
    if not episode.content or not episode.content.strip():
        raise ValueError("Episode content is empty")

    novel_text = episode.content
    global_summary = project.description or ""

    try:
        summary_res = await script_service.summarize_novel(
            novel_text=novel_text,
            global_summary=global_summary,
            user_id=user_id,
        )
        episode.desc = summary_res.get("summary", episode.desc)
    except Exception as e:
        logger.error("Summary extraction failed: %s", e)

    new_assets: list = []
    try:
        char_res = await script_service.extract_characters(
            novel_text=novel_text,
            global_summary=global_summary,
            user_id=user_id,
        )
        for char in char_res.get("characters") or []:
            char_data = dict(char)
            if not char_data.get("desc"):
                char_data["desc"] = f"Character {char_data.get('name')}"
            new_assets.append(
                TypeAdapter(CharacterAsset).validate_python(
                    {"id": str(uuid.uuid4()), "type": "character", **char_data}
                )
            )
        scene_res = await script_service.extract_scenes(
            novel_text=novel_text,
            global_summary=global_summary,
            user_id=user_id,
        )
        for scene in scene_res.get("scenes") or []:
            scene_data = dict(scene)
            if not scene_data.get("desc"):
                scene_data["desc"] = f"Scene {scene_data.get('name')}"
            new_assets.append(
                TypeAdapter(SceneAsset).validate_python(
                    {"id": str(uuid.uuid4()), "type": "scene", **scene_data}
                )
            )
        prop_res = await script_service.extract_props(
            novel_text=novel_text,
            global_summary=global_summary,
            user_id=user_id,
        )
        for prop in prop_res.get("props") or []:
            prop_data = dict(prop)
            if not prop_data.get("desc"):
                prop_data["desc"] = f"Prop {prop_data.get('name')}"
            new_assets.append(
                TypeAdapter(PropAsset).validate_python(
                    {"id": str(uuid.uuid4()), "type": "prop", **prop_data}
                )
            )
    except Exception as e:
        logger.error("Asset extraction failed: %s", e)

    all_assets = (project.assets or []) + new_assets
    known_chars = [a.model_dump() for a in all_assets if a.type == "character"]
    known_scenes = [a.model_dump() for a in all_assets if a.type == "scene"]
    new_storyboards: list = []
    try:
        sb_res = await script_service.split_storyboards(
            novel_text=novel_text,
            project_id=project_id,
            known_characters=known_chars,
            known_scenes=known_scenes,
            user_id=user_id,
        )
        cinematic_defaults = get_cinematic_defaults()
        for idx, sb_item in enumerate(sb_res.get("storyboards") or []):
            char_ids = []
            for char_name in sb_item.get("character_list", []):
                match = next(
                    (a for a in all_assets if a.type == "character" and a.name == char_name),
                    None,
                )
                if match:
                    char_ids.append(match.id)
            prop_ids = []
            for prop_name in sb_item.get("prop_list", []):
                match = next(
                    (a for a in all_assets if a.type == "prop" and a.name == prop_name),
                    None,
                )
                if match:
                    prop_ids.append(match.id)
            scene_name = sb_item.get("location")
            scene_id = None
            if scene_name:
                match = next(
                    (
                        a
                        for a in all_assets
                        if a.type == "scene"
                        and (a.name == scene_name or getattr(a, "location", "") == scene_name)
                    ),
                    None,
                )
                if match:
                    scene_id = match.id
            new_storyboards.append(
                Storyboard(
                    id=str(uuid.uuid4()),
                    episodeId=episode_id,
                    order=idx + 1,
                    shot=sb_item.get("shot_title", f"Shot {idx+1}"),
                    desc=sb_item.get("visual_description", ""),
                    voiceover=sb_item.get("dialogue"),
                    duration=sb_item.get("duration") or "3s",
                    type=sb_item.get("shot_type", "medium"),
                    cameraMovement=sb_item.get("camera_movement"),
                    cameraAngle=sb_item.get("camera_angle") or cinematic_defaults["camera_angle"],
                    lens=sb_item.get("lens") or cinematic_defaults["lens"],
                    focus=sb_item.get("focus") or cinematic_defaults["focus"],
                    lighting=sb_item.get("lighting") or cinematic_defaults["lighting"],
                    colorStyle=sb_item.get("color_style") or cinematic_defaults["color_style"],
                    transition=sb_item.get("transition"),
                    location=sb_item.get("location"),
                    time=sb_item.get("time_of_day"),
                    audioDesc=sb_item.get("audio_description"),
                    sceneId=scene_id,
                    characterIds=char_ids,
                    propIds=prop_ids,
                    originalText=sb_item.get("original_text"),
                    mergeImagePrompt=sb_item.get("merge_image_prompt"),
                    videoPrompt=sb_item.get("video_prompt"),
                    imageUrls=[],
                    videoUrls=[],
                )
            )
    except Exception as e:
        logger.error("Storyboard splitting failed: %s", e)

    project_manager.update_episode(project_id, episode_id, episode)
    if new_assets:
        project_manager.batch_add_assets(project_id, new_assets)
    if new_storyboards:
        project_manager.delete_storyboards_by_episode(project_id, episode_id)
        for sb in new_storyboards:
            project_manager.add_storyboard(project_id, sb)

    final = project_manager.get_project(project_id)
    if not final:
        raise ValueError("Project not found after update")
    return final
