"""Character dataclass and JSON parsing helpers.

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

from __future__ import annotations

import json as _json
from dataclasses import dataclass, field


# -- JSON parsing helpers --------------------------------------------------

def _parse_json_list(raw: str | None) -> list[str]:
    """Safely parse a JSON array of strings; return empty list on failure."""
    if not raw:
        return []
    try:
        data = _json.loads(raw)
        return data if isinstance(data, list) else []
    except (_json.JSONDecodeError, TypeError):
        return []


def _parse_json_list_of_dicts(raw: str | None) -> list[dict]:
    """Safely parse a JSON array of dicts; return empty list on failure."""
    if not raw:
        return []
    try:
        data = _json.loads(raw)
        return data if isinstance(data, list) else []
    except (_json.JSONDecodeError, TypeError):
        return []


def _parse_json_dict(raw: str | None) -> dict:
    """Safely parse a JSON dict; return empty dict on failure."""
    if not raw:
        return {}
    try:
        data = _json.loads(raw)
        return data if isinstance(data, dict) else {}
    except (_json.JSONDecodeError, TypeError):
        return {}


def _parse_secrets(raw: str | None) -> list[dict]:
    """Parse secrets_json: [{content, reveal_condition: {min_affection?, min_trust?}}]"""
    if not raw:
        return []
    try:
        data = _json.loads(raw)
        return data if isinstance(data, list) else []
    except (_json.JSONDecodeError, TypeError):
        return []


# -- Character dataclass ---------------------------------------------------

@dataclass
class Character:
    id: str = ""
    name: str = ""
    personality: str = ""
    background: str = ""
    speaking_style: str = ""
    mbti: str = ""
    greeting: str = ""
    # Phase A extended fields
    appearance: str = ""
    likes: list[str] = field(default_factory=list)
    dislikes: list[str] = field(default_factory=list)
    fears: list[str] = field(default_factory=list)
    quirks: list[str] = field(default_factory=list)
    speech_patterns: str = ""
    secrets: list[dict] = field(default_factory=list)
    default_mood: str = "neutral"
    # Character Card v2
    mes_example: list[dict] = field(default_factory=list)  # [{user, char}]
    post_history_instructions: str = ""
    # Character Card V2 standard fields
    description: str = ""
    personality_summary: str = ""
    scenario: str = ""
    system_prompt: str = ""
    alternate_greetings: list[str] = field(default_factory=list)
    character_book: dict = field(default_factory=dict)  # raw character_book dict
    # Kokoro Extensions
    speech_patterns_v2: dict[str, str] = field(default_factory=dict)  # mood -> pattern
    affection_overrides: dict[str, str] = field(default_factory=dict)  # level -> behavior
    post_history_by_level: dict[str, str] = field(default_factory=dict)  # level -> instructions
    anti_patterns: list[dict] = field(default_factory=list)  # [{bad, correct, why}]

    @classmethod
    def from_db_model(cls, db_char) -> "Character":
        """Build from a DB Character model (duck-typed: only reads attributes)."""
        # Parse Kokoro extensions from JSON blob
        extensions = _parse_json_dict(getattr(db_char, "extensions_json", None))
        kokoro = extensions.get("kokoro", {}) if isinstance(extensions, dict) else {}

        # Parse character_book from dedicated column or top-level YAML field
        character_book = _parse_json_dict(getattr(db_char, "character_book_json", None))

        return cls(
            id=str(db_char.id),
            name=db_char.name or "",
            personality=db_char.personality or "",
            background=db_char.background or "",
            speaking_style=db_char.speaking_style or "",
            mbti=db_char.mbti or "",
            greeting=db_char.greeting or "",
            appearance=db_char.appearance or "",
            likes=_parse_json_list(db_char.likes),
            dislikes=_parse_json_list(db_char.dislikes),
            fears=_parse_json_list(db_char.fears),
            quirks=_parse_json_list(db_char.quirks),
            speech_patterns=db_char.speech_patterns or "",
            secrets=_parse_secrets(db_char.secrets_json),
            default_mood=db_char.default_mood or "neutral",
            mes_example=_parse_json_list_of_dicts(db_char.mes_example),
            post_history_instructions=db_char.post_history_instructions or "",
            # V2 fields
            description=getattr(db_char, "description", "") or "",
            personality_summary=getattr(db_char, "personality_summary", "") or "",
            scenario=getattr(db_char, "scenario", "") or "",
            system_prompt=getattr(db_char, "system_prompt", "") or "",
            alternate_greetings=_parse_json_list(getattr(db_char, "alternate_greetings", None)),
            character_book=character_book,
            # Kokoro extensions
            speech_patterns_v2=kokoro.get("speech_patterns", {}),
            affection_overrides=kokoro.get("affection_overrides", {}),
            post_history_by_level=kokoro.get("post_history_by_level", {}),
            anti_patterns=kokoro.get("anti_patterns", []),
        )
