"""Chat-related web schemas."""

from __future__ import annotations

from typing import Any

try:
    from pydantic import BaseModel, Field
except ModuleNotFoundError:  # pragma: no cover - fallback for skeleton-only environments
    class BaseModel:
        """Very small fallback shim used only so imports work without pydantic."""

        def __init__(self, **kwargs: Any) -> None:
            annotations = getattr(self.__class__, "__annotations__", {})
            for name in annotations:
                default = getattr(self.__class__, name, None)
                if name in kwargs:
                    value = kwargs[name]
                else:
                    value = default
                setattr(self, name, value)

        def model_dump(self, *, exclude_none: bool = False) -> dict[str, Any]:
            data = dict(self.__dict__)
            if exclude_none:
                data = {key: value for key, value in data.items() if value is not None}
            return data

    def Field(default: Any = None, **kwargs: Any) -> Any:
        default_factory = kwargs.get("default_factory")
        if default_factory is not None:
            return default_factory()
        return default


class WebProviderTarget(BaseModel):
    """Web-facing provider target shape.

    先保持和 runtime 里的 `ProviderTarget` 接近，但只暴露 Web 当前需要的字段。
    后面如果 provider 层扩字段，再由这里显式补齐。
    """

    provider: str | None = None
    model: str | None = None
    api_key: str | None = None
    api_base: str | None = None
    extra_headers: dict[str, str] | None = None


class WebChatRequest(BaseModel):
    """最小正式 chat 请求结构。"""

    message: str = Field(min_length=1)
    session_id: str | None = None
    user_id: str | None = None
    title: str | None = None
    execution_context: str | None = None
    prompt_locale: str | None = None
    model: str | None = None
    provider_name: str | None = None
    embedding_model: str | None = None
    temperature: float | None = None
    max_tokens: int | None = None
    thinking_enabled: bool | None = None
    max_tool_iterations: int | None = None
    fallback_target: WebProviderTarget | None = None
    auxiliary_target: WebProviderTarget | None = None
    embedding_target: WebProviderTarget | None = None
    reply_to_scheduled_run_id: str | None = None
    scheduled_reply_intent: str | None = None


class WebChatResponse(BaseModel):
    """最小正式 chat 响应结构。"""

    session_id: str
    run_id: str
    output_text: str
    finish_reason: str
    tool_iterations: int
    provider_name: str | None = None
    model: str | None = None
    usage: dict[str, Any] = Field(default_factory=dict)
    task_id: str | None = None
    task_status: str | None = None
    evidence_status: str | None = None
    acceptance_state: str | None = None
    validation_result: dict[str, Any] | None = None


class WebChatAcceptanceRequest(BaseModel):
    """User acceptance on the latest assistant result in chat."""

    session_id: str
    run_id: str
    acceptance_type: str
    comment: str | None = None


class WebChatAcceptanceResponse(BaseModel):
    """Acceptance recording result."""

    session_id: str
    run_id: str
    task_id: str
    task_status: str
    acceptance_type: str
    feedback_type: str
    learning_candidates: list[dict[str, Any]] = Field(default_factory=list)


class WebChatFeedbackRequest(BaseModel):
    """Backward-compatible feedback payload."""

    session_id: str
    run_id: str
    feedback_type: str
    comment: str | None = None


class WebChatFeedbackResponse(WebChatAcceptanceResponse):
    """Backward-compatible feedback response."""


class WebProviderConfigRequest(BaseModel):
    """Provider config update from the status page."""

    enabled: bool = True
    model: str | None = None
    api_key: str | None = None
    api_base: str | None = None
    request_timeout_seconds: float | None = None


class WebProviderConfigResponse(BaseModel):
    """Provider config update result."""

    ok: bool
    provider: str
    enabled: bool


class WebChannelConfigRequest(BaseModel):
    """Channel config update from the settings page."""

    enabled: bool = False
    kind: str
    mode: str
    account_id: str | None = None
    display_name: str | None = None
    config: dict[str, Any] = Field(default_factory=dict)
    secrets: dict[str, str | None] = Field(default_factory=dict)


class WebChannelConfigResponse(BaseModel):
    """Channel config update result."""

    ok: bool
    channel_id: str
    restart_required: bool
    channel: dict[str, Any]


class WebChannelConnectionCreateRequest(BaseModel):
    """Create a channel connection from the setup UI."""

    kind: str
    mode: str
    display_name: str | None = Field(default=None, alias="displayName")
    owner_user_id: str | None = Field(default=None, alias="ownerUserId")
    auth_type: str = Field(default="token", alias="authType")
    account_id: str | None = Field(default=None, alias="accountId")
    config: dict[str, Any] = Field(default_factory=dict)
    secrets: dict[str, str | None] = Field(default_factory=dict)


class WebChannelConnectionResponse(BaseModel):
    """Channel connection response with redacted credentials."""

    connection: dict[str, Any]
    credentials: dict[str, str] = Field(default_factory=dict)


class WebChannelConnectionUpdateRequest(BaseModel):
    """Update editable channel connection setup fields."""

    display_name: str | None = Field(default=None, alias="displayName")
    account_id: str | None = Field(default=None, alias="accountId")
    config: dict[str, Any] | None = None
    secrets: dict[str, str | None] | None = None


class WebChannelValidationResponse(BaseModel):
    """Connector validation response."""

    ok: bool
    status: str
    account_id: str | None = None
    display_name: str | None = None
    error: str | None = None
    metadata: dict[str, Any] = Field(default_factory=dict)
    connection: dict[str, Any]


class WebConnectorBridgeEventRequest(BaseModel):
    """Inbound connector bridge event from the external sidecar."""

    event_id: str = Field(alias="eventId")
    timestamp: str
    delivery_attempt: int = Field(default=1, alias="deliveryAttempt")
    connection_id: str = Field(alias="connectionId")
    channel_id: str = Field(alias="channelId")
    kind: str
    account_id: str = Field(alias="accountId")
    peer_id: str = Field(alias="peerId")
    peer_type: str = Field(default="unknown", alias="peerType")
    user_id: str | None = Field(default=None, alias="userId")
    thread_id: str | None = Field(default=None, alias="threadId")
    message_id: str = Field(alias="messageId")
    message_type: str = Field(default="text", alias="messageType")
    content: str
    metadata: dict[str, Any] = Field(default_factory=dict)


class WebConnectorBridgeEventResponse(BaseModel):
    """Connector bridge event accept/dedupe response."""

    accepted: bool
    duplicate: bool = False
    pending: bool = False
    retry_after_seconds: int | None = Field(default=None, alias="retryAfterSeconds")


class WebConnectorSessionCreateRequest(BaseModel):
    """Start a connector-managed onboarding session."""

    kind: str
    display_name: str | None = Field(default=None, alias="displayName")
    owner_user_id: str | None = Field(default=None, alias="ownerUserId")
    options: dict[str, Any] = Field(default_factory=dict)


class WebConnectorSessionResponse(BaseModel):
    """Connector session view plus optional connection view."""

    session: dict[str, Any]
    connection: dict[str, Any] | None = None


class WebAgentConfigRequest(BaseModel):
    """Agent runtime defaults update from the settings page."""

    max_tokens: int | None = None
    temperature: float
    max_tool_iterations: int


class WebAgentConfigResponse(BaseModel):
    """Agent runtime defaults update result."""

    ok: bool


class WebStatusResponse(BaseModel):
    """Web 宿主层状态响应。"""

    status: str
    running: bool
    mode: str


class WebErrorResponse(BaseModel):
    """统一错误响应结构。"""

    detail: str
