"""YAML V2 character loader.

Extracted from app/yaml_import.py.
No sqlalchemy/fastapi/redis imports allowed.
"""

from __future__ import annotations

import json


def _dumps_optional(val) -> str | None:
    """Serialize a value to JSON string if not None."""
    if val is None:
        return None
    return json.dumps(val, ensure_ascii=False)


def map_v2_yaml_to_db(data: dict) -> dict:
    """Map Character Card V2 YAML fields to Character DB model kwargs.

    Parameters
    ----------
    data : dict
        Parsed YAML content (top-level dict).

    Returns
    -------
    dict
        Keyword arguments suitable for ``CharacterRepo.create(**kwargs)``.
    """
    extensions = data.get("extensions", {}) or {}
    kokoro = extensions.get("kokoro", {}) or {}

    # --- V2 standard fields ---
    db: dict = {
        "name": data.get("name", ""),
        "description": data.get("description", ""),
        "personality_summary": data.get("personality"),
        "scenario": data.get("scenario"),
        "greeting": data.get("first_mes", ""),
        "system_prompt": data.get("system_prompt"),
        "post_history_instructions": data.get("post_history_instructions"),
        "creator": data.get("creator"),
        "character_version": data.get("character_version"),
    }

    # alternate_greetings -> JSON array
    alt = data.get("alternate_greetings")
    db["alternate_greetings"] = _dumps_optional(alt) if alt else None

    # mes_example -> JSON array
    mes = data.get("mes_example")
    db["mes_example"] = _dumps_optional(mes) if mes else None

    # character_book -> character_book_json (store entire dict as JSON)
    book = data.get("character_book")
    db["character_book_json"] = _dumps_optional(book) if book else None

    # --- Kokoro extension fields -> direct DB columns ---
    db["mbti"] = kokoro.get("mbti", "")
    db["meta"] = kokoro.get("meta")
    db["quote"] = kokoro.get("quote")
    db["avatar_url"] = kokoro.get("avatar_url")
    db["portrait_url"] = kokoro.get("portrait_url")
    db["cover_image_url"] = kokoro.get("cover_image_url")
    db["default_mood"] = kokoro.get("default_mood", "neutral")

    # Kokoro array fields -> JSON columns
    db["likes"] = _dumps_optional(kokoro.get("likes"))
    db["dislikes"] = _dumps_optional(kokoro.get("dislikes"))
    db["fears"] = _dumps_optional(kokoro.get("fears"))
    db["quirks"] = _dumps_optional(kokoro.get("quirks"))
    db["secrets_json"] = _dumps_optional(kokoro.get("secrets"))

    # speech_patterns (could be dict or string)
    sp = kokoro.get("speech_patterns")
    if isinstance(sp, dict):
        db["speech_patterns"] = sp.get("default", "")
    elif isinstance(sp, str):
        db["speech_patterns"] = sp
    else:
        db["speech_patterns"] = ""

    # Use description as personality fallback; V2 has no direct equivalent
    db["personality"] = data.get("description", "")
    db["background"] = ""
    db["speaking_style"] = ""

    # --- Collect non-standard kokoro extension fields into extensions_json ---
    standard_kokoro_keys = {
        "mbti", "speech_patterns", "affection_overrides",
        "post_history_by_level", "anti_patterns", "secrets",
        "likes", "dislikes", "fears", "quirks", "default_mood",
        "meta", "quote", "avatar_url", "portrait_url", "cover_image_url",
    }
    extra_kokoro = {k: v for k, v in kokoro.items() if k not in standard_kokoro_keys}

    # Also include known kokoro-only structured data in extensions_json
    ext_blob: dict = {}
    if kokoro.get("speech_patterns") and isinstance(kokoro["speech_patterns"], dict):
        ext_blob["speech_patterns"] = kokoro["speech_patterns"]
    if kokoro.get("affection_overrides"):
        ext_blob["affection_overrides"] = kokoro["affection_overrides"]
    if kokoro.get("post_history_by_level"):
        ext_blob["post_history_by_level"] = kokoro["post_history_by_level"]
    if kokoro.get("anti_patterns"):
        ext_blob["anti_patterns"] = kokoro["anti_patterns"]
    if extra_kokoro:
        ext_blob.update(extra_kokoro)

    # Non-kokoro extensions
    non_kokoro = {k: v for k, v in extensions.items() if k not in ("kokoro", "kokoro_stories")}
    if non_kokoro:
        ext_blob.update(non_kokoro)

    db["extensions_json"] = _dumps_optional(ext_blob) if ext_blob else None

    return db
