"""
Domain Models

Core domain models for the HoneyDB MCP CLI.
These models are framework-agnostic and represent the business logic.
"""

from datetime import datetime
from typing import Any, Literal
from uuid import uuid4

from pydantic import BaseModel, Field, field_serializer


# Constants
MAX_MESSAGES_PER_SESSION = 1000
MAX_SESSION_SIZE_BYTES = 10 * 1024 * 1024  # 10MB


class Message(BaseModel):
    """Represents a single message in a chat session."""

    role: Literal["user", "assistant", "system"]
    content: str
    timestamp: datetime = Field(default_factory=datetime.now)
    metadata: dict[str, Any] = Field(default_factory=dict)

    @field_serializer('timestamp')
    def serialize_timestamp(self, dt: datetime, _info):
        """Serialize datetime to ISO format string."""
        return dt.isoformat()


class Event(BaseModel):
    """
    Represents an event that occurs during LLM interaction.
    Critical for v2.0: Real-time visibility into MCP tool invocations.
    """

    type: Literal["request_started", "tool_call", "tool_result", "response_received"]
    timestamp: datetime = Field(default_factory=datetime.now)
    data: dict[str, Any] = Field(default_factory=dict)

    @field_serializer('timestamp')
    def serialize_timestamp(self, dt: datetime, _info):
        """Serialize datetime to ISO format string."""
        return dt.isoformat()


class Session(BaseModel):
    """
    Represents a chat session with message history.

    v2.0 Updates:
    - Added size validation (MAX_MESSAGES_PER_SESSION)
    - Enhanced metadata for caching
    """

    id: str = Field(default_factory=lambda: str(uuid4()))
    title: str = "New Session"
    messages: list[Message] = Field(default_factory=list)
    created_at: datetime = Field(default_factory=datetime.now)
    updated_at: datetime = Field(default_factory=datetime.now)
    metadata: dict[str, Any] = Field(default_factory=dict)

    @field_serializer('created_at', 'updated_at')
    def serialize_datetime(self, dt: datetime, _info):
        """Serialize datetime fields to ISO format string."""
        return dt.isoformat()

    def add_message(self, role: Literal["user", "assistant", "system"], content: str) -> None:
        """Add a message to the session."""
        if len(self.messages) >= MAX_MESSAGES_PER_SESSION:
            raise ValueError(
                f"Session has reached maximum size of {MAX_MESSAGES_PER_SESSION} messages. "
                f"Please start a new session or export this one."
            )

        message = Message(role=role, content=content)
        self.messages.append(message)
        self.updated_at = datetime.now()

        # Auto-generate title from first user message
        if not self.title or self.title == "New Session":
            if role == "user" and content.strip():
                self.title = content[:50] + ("..." if len(content) > 50 else "")

    def get_size_bytes(self) -> int:
        """Calculate approximate session size in bytes."""
        # Pydantic v2: field_serializer handles datetime conversion
        return len(self.model_dump_json().encode('utf-8'))

    def validate_size(self) -> None:
        """Validate that session size is within limits."""
        size = self.get_size_bytes()
        if size > MAX_SESSION_SIZE_BYTES:
            raise ValueError(
                f"Session size ({size} bytes) exceeds maximum of {MAX_SESSION_SIZE_BYTES} bytes. "
                f"Please start a new session or export this one."
            )


class SessionMetadata(BaseModel):
    """
    Lightweight session metadata for listing operations.

    v2.0 Critical: Used by persistent metadata cache for 1000x speedup.
    """

    id: str
    title: str
    message_count: int
    created_at: datetime
    updated_at: datetime
    size_bytes: int = 0

    @field_serializer('created_at', 'updated_at')
    def serialize_datetime(self, dt: datetime, _info):
        """Serialize datetime fields to ISO format string."""
        return dt.isoformat()

    @classmethod
    def from_session(cls, session: Session) -> "SessionMetadata":
        """Create metadata from a full session object."""
        return cls(
            id=session.id,
            title=session.title,
            message_count=len(session.messages),
            created_at=session.created_at,
            updated_at=session.updated_at,
            size_bytes=session.get_size_bytes()
        )


class Config(BaseModel):
    """
    Application configuration.

    v2.0 Updates:
    - Added logging configuration
    - Added UI preferences (dark/light mode detection)
    - Added HoneyDB MCP server configuration
    """

    # HoneyDB MCP Configuration
    honeydb_api_id: str | None = None
    honeydb_api_key: str | None = None
    mcp_server_url: str = "https://honeydb.ai/sse/"

    # LLM Configuration
    default_provider: Literal["openai", "anthropic", "gemini"] = "openai"
    openai_api_key: str | None = None
    anthropic_api_key: str | None = None
    gemini_api_key: str | None = None
    default_model: str = "gpt-5.4"
    temperature: float = 0.7
    max_tokens: int | None = None

    # Session Configuration
    auto_save: bool = True
    sessions_dir: str = "~/.honeydb_ai/sessions"

    # UI Configuration
    theme: Literal["auto", "dark", "light"] = "auto"
    markdown_enabled: bool = True
    syntax_highlighting: bool = True
    verbose_tool_calls: bool = False  # Show MCP tool calls only in verbose mode

    # Logging Configuration (v2.0)
    log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO"
    log_file: str = "~/.honeydb_ai/honeydb_ai.log"
    log_max_size_mb: int = 5
    log_backup_count: int = 3

    class Config:
        validate_assignment = True


class LLMResponse(BaseModel):
    """Response from an LLM provider."""

    content: str
    model: str
    finish_reason: str | None = None
    usage: dict[str, Any] = Field(default_factory=dict)
    metadata: dict[str, Any] = Field(default_factory=dict)
