"""Core data types for Logos ADK."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

from pydantic import BaseModel


@dataclass
class ContentPart:
    """Single multimodal content block."""

    type: str  # "text", "image", "video", "audio", "file", "artifact"
    text: str | None = None
    uri: str | None = None
    data: str | None = None
    mime_type: str | None = None
    name: str | None = None
    metadata: dict[str, Any] = field(default_factory=dict)


def normalize_content_parts(value: Any) -> list[ContentPart]:
    """Normalize raw values into ContentPart objects."""
    if value is None:
        return []
    if isinstance(value, ContentPart):
        return [value]
    if isinstance(value, list):
        parts: list[ContentPart] = []
        for item in value:
            if isinstance(item, ContentPart):
                parts.append(item)
                continue
            if isinstance(item, dict):
                parts.append(
                    ContentPart(
                        type=str(item.get("type", "text")),
                        text=item.get("text"),
                        uri=item.get("uri"),
                        data=item.get("data"),
                        mime_type=item.get("mime_type"),
                        name=item.get("name"),
                        metadata=dict(item.get("metadata") or {}),
                    )
                )
                continue
            raise TypeError(f"Unsupported content part type: {type(item).__name__}")
        return parts
    raise TypeError(f"Unsupported content parts payload: {type(value).__name__}")


def content_text(content: str | None, content_parts: list[ContentPart] | None = None) -> str:
    """Return a text representation for mixed text/media payloads."""
    if isinstance(content, str) and content.strip():
        return content
    parts = normalize_content_parts(content_parts)
    rendered: list[str] = []
    for part in parts:
        if part.type == "text" and part.text:
            rendered.append(part.text)
            continue
        label = part.name or part.mime_type or part.uri or part.type
        rendered.append(f"[{part.type}: {label}]")
    return "\n".join(item for item in rendered if item).strip()


def has_media_content(content_parts: list[ContentPart] | None = None) -> bool:
    """Return True when payload includes non-text multimodal parts."""
    return any(part.type != "text" for part in normalize_content_parts(content_parts))


@dataclass
class ToolCall:
    """Request from LLM to call a tool."""

    id: str
    name: str
    arguments: dict[str, Any]


@dataclass
class ToolResult:
    """Result of a tool execution."""

    call_id: str
    content: Any
    content_parts: list[ContentPart] = field(default_factory=list)
    error: str | None = None
    duration_ms: float = 0
    status: str = "completed"  # "completed", "failed", "paused"


@dataclass
class Usage:
    """Token usage statistics."""

    input_tokens: int
    output_tokens: int


@dataclass
class Message:
    """A message in the conversation."""

    role: str  # "user", "assistant", "system", "tool"
    content: str
    content_parts: list[ContentPart] = field(default_factory=list)
    sender: str | None = None  # Name of the agent or user who sent this
    tool_calls: list[ToolCall] = field(default_factory=list)
    tool_result: ToolResult | None = None


@dataclass
class Response:
    """Response from an LLM provider."""

    content: str
    tool_calls: list[ToolCall]
    usage: Usage
    raw: dict
    content_parts: list[ContentPart] = field(default_factory=list)
    reasoning: str | None = None  # Extended thinking/reasoning from model
    status: str = "completed"  # "completed", "failed", "paused"


@dataclass
class StructuredResponse(Response):
    """Response with parsed structured output."""

    parsed: BaseModel | None = None


@dataclass
class TextChunk:
    """A chunk of streamed text."""

    text: str
    reasoning: str | None = None  # Reasoning chunk during streaming
    type: str = "text"


@dataclass
class MediaChunk:
    """A chunk of streamed media content."""

    part: ContentPart
    type: str = "media"


@dataclass
class ToolStart:
    """Signals the start of a tool call during streaming."""

    call_id: str
    name: str
    arguments: dict[str, Any]
    type: str = "tool_start"


@dataclass
class ToolEnd:
    """Signals the completion of a tool call during streaming."""

    call_id: str
    result: ToolResult
    type: str = "tool_end"


@dataclass
class AgentDelegation:
    """Signals delegation to another agent."""

    from_agent: str
    to_agent: str
    message_type: str
    type: str = "agent_delegation"


@dataclass
class StreamDone:
    """Signals the end of a streaming response."""

    response: Response
    type: str = "done"


StreamChunk = TextChunk | MediaChunk | ToolStart | ToolEnd | AgentDelegation | StreamDone
