"""아웃룩 추출 — 전체 씬 + 캐릭터 목록 → 아웃룩 전체 매핑 (1회 호출).

Gemini 3.1 Pro에 전체 씬 JSON + 캐릭터 목록을 보내서
모든 아웃룩을 한번에 추출하고, 씬별 캐릭터-아웃룩 연결을 생성.
결과는 JSON으로 저장.
"""

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

from app.core.config import settings
from app.modules.llm.gemini_text_client import GeminiTextClient

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

logger = logging.getLogger(__name__)


def _load_prompt(**kwargs) -> str:
    versions = sorted([d.name for d in PROMPT_DIR.iterdir() if d.is_dir()], reverse=True)
    text = (PROMPT_DIR / versions[0] / "extract_prompt.md").read_text(encoding="utf-8").strip()
    return text.format(**kwargs)


def _load_schema() -> Dict[str, Any]:
    versions = sorted([d.name for d in PROMPT_DIR.iterdir() if d.is_dir()], reverse=True)
    return json.loads((PROMPT_DIR / versions[0] / "extract_schema.json").read_text(encoding="utf-8"))


def extract_all_outlooks(
    segments: List[Dict[str, Any]],
    fulltext: str,
    characters: List[str],
    checkpoint_dir: Optional[str] = None,
    project_llm_config: Optional[Dict[str, Any]] = None,
) -> Dict[str, Any]:
    """전체 씬 + 캐릭터 → 아웃룩 전체 매핑.

    Args:
        segments: 분할된 씬 목록 [{scene_index, heading, start_char, end_char, length}]
        fulltext: 시나리오 전문
        characters: 확정된 캐릭터 이름 목록
        checkpoint_dir: (unused, kept for API compat)

    Returns:
        {
            "outlooks": [{name, description, is_shared}],
            "scene_assignments": [{scene_index, characters: [{character_name, outlook_name}]}]
        }
    """
    # 씬 JSON 구성 (씬 텍스트 포함)
    scenes_json = []
    for seg in segments:
        scene_text = fulltext[seg["start_char"]:seg["end_char"]]
        scenes_json.append({
            "scene_index": seg["scene_index"],
            "heading": seg["heading"],
            "text": scene_text,
        })

    character_list = "\n".join(f"- {name}" for name in characters)
    scenes_json_str = json.dumps(scenes_json, ensure_ascii=False, indent=1)

    prompt = _load_prompt(
        character_list=character_list,
        scenes_json=scenes_json_str,
    )
    schema = _load_schema()

    # LLM 라우터를 통해 호출 (프로젝트 설정에 따라 provider/model 선택)
    from app.modules.llm.llm_router import call_structured
    logger.info("Outlook extraction: %d scenes, %d characters",
                len(segments), len(characters))

    system_instruction = "영화 의상 담당자. 각 인물의 복장을 정확히 구분하고 시각적으로 상세히 디자인한다."
    result = None
    for retry in range(3):
        try:
            result = call_structured(
                step="outlook_extraction",
                system_prompt=system_instruction,
                user_prompt=prompt,
                response_schema=schema,
                project_llm_config=project_llm_config,
                schema_name="outlook_extraction",
            )
            break
        except Exception as exc:
            logger.warning("Outlook extraction attempt %d failed: %s", retry + 1, exc)
            if retry < 2:
                import time
                time.sleep(5 * (retry + 1))

    if not result:
        logger.error("Outlook extraction failed after all retries")
        return {"outlooks": [], "scene_assignments": []}

    outlooks = result.get("outlooks", [])
    assignments = result.get("scene_assignments", [])
    logger.info("Outlook extraction complete: %d outlooks, %d scene assignments",
                len(outlooks), len(assignments))

    return result
