import uuid
from typing import Optional, Any, List, Dict
from typing_extensions import Literal
from pydantic import BaseModel, Field, field_validator, UUID4, ConfigDict
from time import time

from gwenflow.types import Message, Usage


class Function(BaseModel):
    name: str
    arguments: str

class ToolCall(BaseModel):
    id: str
    function: Function
    type: Literal["function"]

class ToolResponse(BaseModel):
    tool_call_id: str
    tool_name: str
    tool_args: Optional[Dict[str, Any]] = None
    tool_call_error: Optional[bool] = None
    result: Optional[str] = None
    usage: Optional[Usage] = None
    created_at: int = Field(default_factory=lambda: int(time()))

    def to_message(self) -> Message:
        return Message(
            role="tool",
            tool_call_id=self.tool_call_id,
            tool_name=self.tool_name,
            content=self.result,
        )

class ModelResponse(BaseModel):

    id: str = Field(default_factory=lambda: str(uuid.uuid4()))

    role: Optional[str] = None

    content: Optional[str] = None
    parsed: Optional[Any] = None
    reasoning_content: Optional[str] = None
    tool_calls: List[ToolCall] = Field(default_factory=list)

    finish_reason: Optional[str] = None
    usage: Optional[Usage] = None

    created_at: int = Field(default_factory=lambda: int(time()))

    def to_message(self) -> Message:
        return Message(**self.model_dump(exclude_unset=True))


class AgentResponse(BaseModel):

    id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
    """The id of the response."""

    content: Optional[str] = None
    parsed: Optional[Any] = None
    reasoning_content: Optional[str] = None

    messages: list[Message] = Field(default_factory=list)
    """A list of messages generated by the agent."""

    finish_reason: Optional[str] = None
    usage: Usage = Field(default_factory=Usage)

    created_at: int = Field(default_factory=lambda: int(time()))

    model_config = ConfigDict(arbitrary_types_allowed=True)

    @field_validator("id", mode="before")
    @classmethod
    def deny_user_set_id(cls, v: Optional[UUID4]) -> None:
        if v:
            raise ValueError("This field is not to be set by the user.")

    def to_messages(self) -> list[Message]:
        """Convert the output into a list of input items suitable for passing to the model."""
        return [Message(**it.model_dump(exclude_unset=True)) for it in self.messages]  # type: ignore