"""Data models for the Sigil SDK."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


@dataclass
class Voice:
    """Voice configuration for a persona."""

    tone: list[str] = field(default_factory=list)
    dos: list[str] = field(default_factory=list)
    donts: list[str] = field(default_factory=list)
    example_phrases: list[str] = field(default_factory=list)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Voice:
        return cls(
            tone=data.get("tone", []),
            dos=data.get("dos", []),
            donts=data.get("donts", []),
            example_phrases=data.get("example_phrases", []),
        )


@dataclass
class Value:
    """A persona value with priority."""

    name: str
    description: str
    priority: int = 0

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Value:
        return cls(
            name=data.get("name", ""),
            description=data.get("description", ""),
            priority=data.get("priority", 0),
        )


@dataclass
class BehavioralEntry:
    """A behavioral map entry."""

    posture: str
    example: str

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> BehavioralEntry:
        return cls(
            posture=data.get("posture", ""),
            example=data.get("example", ""),
        )


@dataclass
class Identity:
    """Persona identity information."""

    name: str
    version: str
    description: str = ""

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> Identity:
        return cls(
            name=data.get("name", ""),
            version=data.get("version", ""),
            description=data.get("description", ""),
        )


@dataclass
class TestCase:
    """A test case for persona validation."""

    id: str
    description: str
    prompt: str
    expected_behavior: str

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> TestCase:
        return cls(
            id=data.get("id", ""),
            description=data.get("description", ""),
            prompt=data.get("prompt", ""),
            expected_behavior=data.get("expected_behavior", ""),
        )


@dataclass
class PersonaDocument:
    """The full persona document from the API."""

    identity: Identity
    soul: str
    voice: Voice
    values: list[Value]
    behavioral_map: dict[str, BehavioralEntry]
    test_cases: list[TestCase]

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> PersonaDocument:
        identity_data = data.get("identity", {})
        voice_data = data.get("voice", {})
        values_data = data.get("values", [])
        behavioral_data = data.get("behavioral_map", {})
        test_cases_data = data.get("test_cases", [])

        return cls(
            identity=Identity.from_dict(identity_data),
            soul=data.get("soul", ""),
            voice=Voice.from_dict(voice_data),
            values=[Value.from_dict(v) for v in values_data],
            behavioral_map={
                k: BehavioralEntry.from_dict(v) for k, v in behavioral_data.items()
            },
            test_cases=[TestCase.from_dict(tc) for tc in test_cases_data],
        )


@dataclass
class Persona:
    """A Sigil persona with inject capabilities."""

    name: str
    version: str
    document: PersonaDocument

    @property
    def soul(self) -> str:
        """Get the soul/system text."""
        return self.document.soul

    @property
    def voice(self) -> Voice:
        """Get the voice configuration."""
        return self.document.voice

    @property
    def values(self) -> list[Value]:
        """Get the persona values."""
        return self.document.values

    @property
    def behavioral_map(self) -> dict[str, BehavioralEntry]:
        """Get the behavioral map."""
        return self.document.behavioral_map

    def inject(self, base: str | None = None) -> str:
        """
        Compose a system prompt from the persona fields.

        Args:
            base: Optional base prompt to prepend.

        Returns:
            A formatted system prompt string.
        """
        from sigil.inject import compose_prompt

        return compose_prompt(self, base=base)

    @classmethod
    def from_api_response(cls, data: dict[str, Any]) -> Persona:
        """Create a Persona from an API response."""
        persona_data = data.get("persona", {})
        return cls(
            name=data.get("name", ""),
            version=data.get("version", ""),
            document=PersonaDocument.from_dict(persona_data),
        )
