# platform/interface.py
from __future__ import annotations

from collections.abc import AsyncIterator
from datetime import datetime
from typing import Any, Literal, Protocol

from pydantic import BaseModel, Field


class User(BaseModel):
    user_id: str
    external_id: str
    platform: str
    display_name: str | None = None
    created_at: datetime
    is_new: bool = False


class Attachment(BaseModel):
    url: str | None = None
    mime_type: str | None = None
    size: int | None = None
    filename: str | None = None
    workspace_path: str | None = None


class MessageResponse(BaseModel):
    message_id: str
    response: str
    tokens_used: int
    finished: bool
    attachments: list[Attachment] = Field(default_factory=list)


class MessageChunk(BaseModel):
    """Один кусок стримингового ответа. При sync-режиме — единственный чанк с finished=True."""

    message_id: str
    delta: str
    finished: bool
    tokens_used: int = 0


class UserSettings(BaseModel):
    skills: dict[str, bool] = {}
    connectors: dict[str, dict] = {}
    soul: dict[str, str] = {}  # свободные поля: name, instructions и т.п. — без пресетов стилей
    safety: dict[str, bool] = {}
    plan: dict[str, Any] = {}


class AgentEvent(BaseModel):
    """Webhook-уведомление от платформы — агент закончил долгую задачу."""

    event_id: str
    user_id: str
    chat_id: str
    event_type: Literal["task_done", "task_error", "task_progress"]
    payload: dict[str, Any] = {}


class PlatformError(Exception):
    def __init__(self, message: str, code: str = "PLATFORM_ERROR"):
        super().__init__(message)
        self.code = code


class PlatformClient(Protocol):
    async def get_or_create_user(
        self,
        external_id: str,
        platform: str,
        display_name: str | None = None,
    ) -> User: ...

    # Sync — используем сейчас
    async def send_message(
        self,
        user_id: str,
        chat_id: str,
        text: str,
        attachments: list[Attachment] | None = None,
    ) -> MessageResponse: ...

    # Streaming — дверь открыта, мок отдаёт один чанк
    async def stream_message(
        self,
        user_id: str,
        chat_id: str,
        text: str,
        attachments: list[Attachment] | None = None,
    ) -> AsyncIterator[MessageChunk]: ...

    async def get_settings(self, user_id: str) -> UserSettings: ...

    async def update_settings(self, user_id: str, action: Any) -> None: ...


class WebhookReceiver(Protocol):
    """Регистрируется в боте. Платформа зовёт нас когда агент закончил долгую задачу."""

    async def on_agent_event(self, event: AgentEvent) -> None: ...
