from __future__ import annotations

from dataclasses import asdict, dataclass, field
from typing import Any, Awaitable, Callable, Literal, Protocol

SecurityMode = Literal["safe", "yolo", "god"]
TELEGRAM_ACTIVE_USER_ID_METADATA_KEY = "telegram_active_user_id"


@dataclass
class ChatMessage:
    role: str
    content: Any
    name: str | None = None
    tool_call_id: str | None = None
    metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        payload: dict[str, Any] = {"role": self.role, "content": self.content}
        if self.name:
            payload["name"] = self.name
        if self.tool_call_id:
            payload["tool_call_id"] = self.tool_call_id
        if self.metadata:
            payload["metadata"] = self.metadata
        return payload

    @classmethod
    def from_dict(cls, payload: dict[str, Any]) -> "ChatMessage":
        return cls(
            role=str(payload.get("role", "user")),
            content=payload.get("content"),
            name=payload.get("name"),
            tool_call_id=payload.get("tool_call_id"),
            metadata=payload.get("metadata", {}) or {},
        )


@dataclass
class ToolCall:
    id: str
    name: str
    arguments: dict[str, Any]


@dataclass
class GenerationResult:
    text: str
    tool_calls: list[ToolCall] = field(default_factory=list)
    usage: dict[str, Any] = field(default_factory=dict)
    model: str = ""
    provider: str = ""
    raw: dict[str, Any] = field(default_factory=dict)


@dataclass
class SessionState:
    session_id: str
    chat_id: str
    user_id: int | None
    provider: str
    model: str
    security_mode: SecurityMode = "safe"
    history: list[ChatMessage] = field(default_factory=list)
    enabled_skills: list[str] = field(default_factory=list)
    metadata: dict[str, Any] = field(default_factory=dict)
    closed: bool = False

    def to_dict(self) -> dict[str, Any]:
        payload = asdict(self)
        payload["history"] = [message.to_dict() for message in self.history]
        return payload

    @classmethod
    def from_dict(cls, payload: dict[str, Any]) -> "SessionState":
        return cls(
            session_id=str(payload["session_id"]),
            chat_id=str(payload.get("chat_id", payload["session_id"])),
            user_id=payload.get("user_id"),
            provider=str(payload.get("provider", "openai")),
            model=str(payload.get("model", "")),
            security_mode=payload.get("security_mode", "safe"),
            history=[ChatMessage.from_dict(item) for item in payload.get("history", [])],
            enabled_skills=list(payload.get("enabled_skills", [])),
            metadata=dict(payload.get("metadata", {})),
            closed=bool(payload.get("closed", False)),
        )


ToolHandler = Callable[["ToolExecutionContext", dict[str, Any]], Any | Awaitable[Any]]


@dataclass
class ToolDefinition:
    name: str
    description: str
    parameters: dict[str, Any]
    handler: ToolHandler
    owner_only: bool = True
    destructive: bool = False

    def openai_schema(self) -> dict[str, Any]:
        return {
            "type": "function",
            "function": {
                "name": self.name,
                "description": self.description,
                "parameters": self.parameters,
            },
        }


@dataclass
class ToolExecutionContext:
    runtime: Any
    session: SessionState
    config: dict[str, Any]
    chat_id: str
    user_id: int | None
    is_owner: bool
    transport: str = "local"
    transport_state: dict[str, Any] = field(default_factory=dict)


class ProviderClient(Protocol):
    async def generate(
        self,
        messages: list[dict[str, Any]],
        tools: list[dict[str, Any]],
        model: str,
        system_prompt: str | None = None,
        temperature: float | None = None,
    ) -> dict[str, Any]: ...

    async def list_models(self) -> list[str]: ...
