"""T2I 시각적 프롬프트 변환 모듈 — 분석 단계에서 요소/씬을 시각적 보통명사 T2I 프롬프트로 변환."""

import json
from pathlib import Path
from typing import Any, Dict, List

from app.modules.llm.base import BaseLLMClient

PROMPT_DIR = (
    Path(__file__).resolve().parent.parent.parent.parent
    / "prompts" / "_base" / "t2i_visual_converter" / "v3"
)

# Entity T2I prompt schema
ENTITY_T2I_SCHEMA: Dict[str, Any] = {
    "type": "object",
    "additionalProperties": False,
    "properties": {
        "entities": {
            "type": "array",
            "items": {
                "type": "object",
                "additionalProperties": False,
                "properties": {
                    "id": {"type": "string"},
                    "t2i_prompt": {"type": "string"},
                },
                "required": ["id", "t2i_prompt"],
            },
        },
    },
    "required": ["entities"],
}

# Scene T2I prompt schema — 씬당 1개 프롬프트
SCENE_T2I_SCHEMA: Dict[str, Any] = {
    "type": "object",
    "additionalProperties": False,
    "properties": {
        "scenes": {
            "type": "array",
            "items": {
                "type": "object",
                "additionalProperties": False,
                "properties": {
                    "id": {"type": "string"},
                    "t2i_prompt": {"type": "string"},
                },
                "required": ["id", "t2i_prompt"],
            },
        },
    },
    "required": ["scenes"],
}


class T2IVisualConverter:
    """요소/씬 description을 시각적 보통명사 기반 T2I 프롬프트로 변환."""

    def __init__(self, llm_client: BaseLLMClient) -> None:
        self._llm = llm_client
        self._system_prompt = (PROMPT_DIR / "system.md").read_text(encoding="utf-8").strip()

    def convert_entities(
        self, entities: List[Dict[str, Any]],
    ) -> Dict[str, str]:
        """엔티티 리스트 → {entity_id: t2i_prompt} 매핑.

        Args:
            entities: [{"id", "name", "entity_type", "description", "stable_traits"}, ...]

        Returns:
            {entity_id: t2i_prompt_string}
        """
        if not entities:
            return {}

        user_prompt = "Convert the following entity descriptions into T2I visual prompts.\n\n"
        for e in entities:
            traits = e.get("stable_traits", "{}")
            if isinstance(traits, str):
                try:
                    traits_data = json.loads(traits)
                except json.JSONDecodeError:
                    traits_data = {}
            else:
                traits_data = traits
            visual_traits = traits_data.get("visual_anchor_traits", [])
            traits_str = ", ".join(visual_traits) if visual_traits else "(none)"

            user_prompt += (
                f"- ID: {e['id']}\n"
                f"  Type: {e['entity_type']}\n"
                f"  Name (for context only, do NOT use in prompt): {e['name']}\n"
                f"  Description: {e.get('description', '')}\n"
                f"  Visual traits: {traits_str}\n\n"
            )

        result = self._llm.generate_structured(
            system_prompt=self._system_prompt,
            user_prompt=user_prompt,
            response_schema=ENTITY_T2I_SCHEMA,
            schema_name="entity_t2i",
        )
        return {item["id"]: item["t2i_prompt"] for item in result.get("entities", [])}

    def convert_scenes(
        self,
        scenes: List[Dict[str, Any]],
        entity_t2i_map: Dict[str, str],
    ) -> Dict[str, str]:
        """씬 리스트 → {scene_id: t2i_prompt} 매핑.

        Args:
            scenes: [{"id", "still_frame_prompt", "visible_entities_json", ...}, ...]
            entity_t2i_map: {entity_id: t2i_prompt} for reference

        Returns:
            {scene_id: t2i_prompt_string}
        """
        if not scenes:
            return {}

        user_prompt = (
            "아래 장면 설명을 T2I 이미지 생성용 한국어 프롬프트로 변환하세요.\n"
            "각 씬에 대해 프롬프트 1개를 생성합니다.\n\n"
            "## [마커] 규칙 — 반드시 준수\n"
            "1. 각 씬 아래의 '★ 엔티티 목록'에 있는 이름만 [이름] 마커 사용 가능\n"
            "2. 목록에 없는 이름은 절대 [] 마커 금지. 일반 명사로 서술\n"
            "3. [이름]은 목록의 이름을 공백 포함 정확히 복사 (예: [장소 이름] O, [장소이름] X)\n"
            "4. [] 마커는 참조 이미지 치환용이므로 목록 외 사용 시 시스템 오류 발생\n\n"
        )

        for s in scenes:
            vis_json = s.get("visible_entities_json", "[]")
            try:
                vis_list = json.loads(vis_json) if isinstance(vis_json, str) else vis_json
            except json.JSONDecodeError:
                vis_list = []

            # Build entity list with names and visual descriptions
            entity_refs = []
            for v in vis_list:
                if isinstance(v, dict):
                    eid = v.get("entity_id", "")
                    ename = v.get("entity_name", "")
                    t2i = entity_t2i_map.get(eid, "")
                    if ename:
                        entity_refs.append(f"[{ename}] → {t2i or '(no visual ref)'}")

            entity_ref_str = "\n    ".join(entity_refs) if entity_refs else "(none)"

            user_prompt += (
                f"- ID: {s['id']}\n"
                f"  씬 설명: {s.get('still_frame_prompt', '')}\n"
                f"  씬 헤딩: {s.get('screenplay_scene_heading', '')}\n"
                f"  ★ [마커] 사용 가능한 엔티티 목록 (이 목록에 없는 이름은 [] 금지):\n    {entity_ref_str}\n"
                f"  ★ 목록에 없는 대상은 보통명사로 서술 ([] 마커 금지)\n\n"
            )

        result = self._llm.generate_structured(
            system_prompt=self._system_prompt,
            user_prompt=user_prompt,
            response_schema=SCENE_T2I_SCHEMA,
            schema_name="scene_t2i",
        )
        return {
            item["id"]: item["t2i_prompt"]
            for item in result.get("scenes", [])
        }
