"""Connectors domain — Pydantic schemas."""
from __future__ import annotations

from datetime import datetime
from typing import Any, Literal, Optional
from uuid import UUID

from pydantic import BaseModel, Field

PermissionMode = Literal["allow", "deny", "ask"]


class ConnectorChangelogEntryResponse(BaseModel):
    version: str
    date: str
    notes: str


class ConnectorFieldResponse(BaseModel):
    key: str
    label: str
    description: Optional[str] = None
    placeholder: Optional[str] = None
    required: bool = False
    input_type: str = "text"
    default: Optional[str] = None


class ConnectorActionResponse(BaseModel):
    id: Optional[UUID] = None
    connector_id: Optional[UUID] = None
    action_key: str
    slug: str
    name: str
    description: Optional[str] = None
    input_schema: dict[str, Any] = Field(default_factory=dict)
    output_schema: dict[str, Any] = Field(default_factory=dict)
    execution_mode: str = "sync"
    required_scopes: list[str] = Field(default_factory=list)
    required_capabilities: list[str] = Field(default_factory=list)
    implements: list[str] = Field(default_factory=list)


class ConnectorTriggerResponse(BaseModel):
    id: Optional[UUID] = None
    connector_id: Optional[UUID] = None
    trigger_key: str
    event_type: str
    name: str
    webhook_required: bool = True
    polling_supported: bool = False
    schema_info: dict[str, Any] = Field(default_factory=dict, alias="schema")

    model_config = {"populate_by_name": True}


class ConnectorResponse(BaseModel):
    authorization: dict[str, Any] | None = None
    id: Optional[UUID] = None
    key: str
    name: str
    category: str
    auth_type: str
    ownership_mode: str = "customer_byok"
    execution_domain: str = "C"
    version: str = "01.00.00"
    status: str
    client_side: bool = False
    icon: Optional[str] = None
    image_url: Optional[str] = None
    description: Optional[str] = None
    docs_url: Optional[str] = None
    credential_check: str = "fields"
    credential_check_note: Optional[str] = None
    config_fields: list[str] = Field(default_factory=list)
    secret_fields: list[str] = Field(default_factory=list)
    config_field_defs: list[ConnectorFieldResponse] = Field(default_factory=list)
    secret_field_defs: list[ConnectorFieldResponse] = Field(default_factory=list)
    actions: list[ConnectorActionResponse] = Field(default_factory=list)
    triggers: list[ConnectorTriggerResponse] = Field(default_factory=list)
    changelog: list[ConnectorChangelogEntryResponse] = Field(default_factory=list)


class CreateConnectorConnectionRequest(BaseModel):
    provider_connection_id: UUID | None = None
    connector_key: str
    name: str = Field(..., min_length=1, max_length=80)
    config: dict[str, Any] = Field(default_factory=dict)
    secrets: dict[str, str] = Field(default_factory=dict)
    scopes: list[str] = Field(default_factory=list)
    permissions: dict[str, PermissionMode] = Field(default_factory=dict)


class UpdateConnectorConnectionRequest(BaseModel):
    name: Optional[str] = Field(None, min_length=1, max_length=80)
    status: Optional[Literal[
        "active",
        "disconnected",
        "error",
        "pending",
        "reauthentication_required",
    ]] = None
    config: Optional[dict[str, Any]] = None
    scopes: Optional[list[str]] = None


class RotateConnectorSecretsRequest(BaseModel):
    secrets: dict[str, str]


class ConnectorPermissionResponse(BaseModel):
    id: UUID
    connection_id: UUID
    action_slug: str
    mode: str
    policy: Optional[dict[str, Any]] = None
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class UpsertConnectorPermissionRequest(BaseModel):
    action_slug: str
    mode: PermissionMode
    policy: Optional[dict[str, Any]] = None


class CreateConnectorApprovalRequest(BaseModel):
    action_slug: str
    run_id: Optional[UUID] = None
    ttl_minutes: int = Field(10, ge=1, le=60)


class ConnectorApprovalResponse(BaseModel):
    approval_token: str
    expires_at: datetime


class ExecuteConnectorActionRequest(BaseModel):
    action: str = Field(..., min_length=1, max_length=128)
    input: dict[str, Any] = Field(default_factory=dict)
    idempotency_key: Optional[str] = Field(None, max_length=128)


class ExecuteConnectorActionResponse(BaseModel):
    ok: bool
    job_id: str
    status: str
    poll_url: Optional[str] = None


class InvokeMessagingSendRequest(BaseModel):
    destination: str = Field(..., min_length=1)
    text: str = Field(..., min_length=1)
    thread_ref: Optional[str] = None
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    destination_map: Optional[dict[str, str]] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeMessagingSendResponse(BaseModel):
    capability: str = "messaging.send"
    status: str
    message_id: Optional[str] = None
    thread_ref: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeAutomationWorkflowTriggerRequest(BaseModel):
    workflow: str = Field(..., min_length=1)
    input: dict[str, Any]
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    workflow_map: Optional[dict[str, UUID]] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeAutomationWorkflowTriggerResponse(BaseModel):
    capability: str = "automation.workflow.trigger"
    status: str
    execution_ref: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeEmailSendRequest(BaseModel):
    to: str | list[str]
    subject: str = Field(..., min_length=1)
    text: str = Field(..., min_length=1)
    html: Optional[str] = None
    reply_to: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeEmailSendResponse(BaseModel):
    capability: str = "email.send"
    status: str
    message_id: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeMessagingSmsSendRequest(BaseModel):
    destination: str = Field(..., min_length=1)
    text: str = Field(..., min_length=1)
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeMessagingSmsSendResponse(BaseModel):
    capability: str = "messaging.sms.send"
    status: str
    message_id: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokePaymentsCheckoutRequest(BaseModel):
    success_url: str
    cancel_url: str
    items: list[dict[str, Any]]
    customer_email: Optional[str] = None
    kind: Optional[str] = None
    capture_mode: Optional[str] = None
    related_order_id: Optional[str] = None
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokePaymentsCaptureRequest(BaseModel):
    order_id: str
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokePaymentsRefundRequest(BaseModel):
    order_id: str
    amount: Optional[int] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokePaymentsCatalogRequest(BaseModel):
    name: str
    unit_amount: int
    currency: str
    description: Optional[str] = None
    sku: Optional[str] = None
    product_record_id: Optional[str] = None
    price_record_id: Optional[str] = None
    interval: Optional[str] = None
    active: Optional[bool] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokePaymentsResponse(BaseModel):
    capability: str
    status: str
    execution_ref: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeDocumentRequest(BaseModel):
    title: Optional[str] = None
    document: Optional[str] = None
    text: Optional[str] = None
    position: Optional[str] = None
    find: Optional[str] = None
    replace: Optional[str] = None
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    document_map: Optional[dict[str, UUID]] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeDocumentResponse(BaseModel):
    capability: str
    status: str
    document: Optional[dict[str, Any]] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeCrmContactRequest(BaseModel):
    contact: Optional[dict[str, Any]] = None
    changes: Optional[dict[str, Any]] = None
    email: Optional[str] = None
    cursor: Optional[str] = None
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeCrmContactResponse(BaseModel):
    capability: str
    status: str
    contact: Optional[dict[str, Any]] = None
    items: Optional[list[dict[str, Any]]] = None
    next_cursor: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeCrmCompanyRequest(BaseModel):
    company: Optional[dict[str, Any]] = None
    changes: Optional[dict[str, Any]] = None
    name: Optional[str] = None
    cursor: Optional[str] = None
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeCrmCompanyResponse(BaseModel):
    capability: str
    status: str
    company: Optional[dict[str, Any]] = None
    items: Optional[list[dict[str, Any]]] = None
    next_cursor: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeCrmDealRequest(BaseModel):
    deal: Optional[dict[str, Any]] = None
    changes: Optional[dict[str, Any]] = None
    name: Optional[str] = None
    stage: Optional[str] = None
    cursor: Optional[str] = None
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeCrmDealResponse(BaseModel):
    capability: str
    status: str
    deal: Optional[dict[str, Any]] = None
    items: Optional[list[dict[str, Any]]] = None
    next_cursor: Optional[str] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class InvokeCrmAssociationRequest(BaseModel):
    association: Optional[dict[str, Any]] = None
    metadata: Optional[dict[str, Any]] = None
    provider_hint: Optional[str] = None
    binding_connection_id: Optional[UUID] = None
    approval_token: Optional[str] = None
    idempotency_key: Optional[str] = Field(None, max_length=128)


class InvokeCrmAssociationResponse(BaseModel):
    capability: str
    status: str
    association: Optional[dict[str, Any]] = None
    reason_code: Optional[str] = None
    message: Optional[str] = None


class WorkspaceConnectorDefaultResponse(BaseModel):
    id: UUID
    workspace_id: UUID
    connector_key: str
    config: Optional[dict[str, Any]] = None
    secrets_configured: list[str] = Field(default_factory=list)
    scopes: list[str] = Field(default_factory=list)
    default_permissions: dict[str, str] = Field(default_factory=dict)
    created_at: datetime
    updated_at: datetime

    model_config = {"from_attributes": True}


class UpsertWorkspaceConnectorDefaultRequest(BaseModel):
    config: dict[str, Any] = Field(default_factory=dict)
    secrets: dict[str, str] = Field(default_factory=dict)
    scopes: list[str] = Field(default_factory=list)
    default_permissions: dict[str, PermissionMode] = Field(default_factory=dict)


class CopyFromWorkspaceDefaultRequest(BaseModel):
    connector_key: str
    name: str = Field(..., min_length=1, max_length=80)


class ConnectorConnectionResponse(BaseModel):
    provider_connection_id: UUID | None = None
    id: UUID
    connector_id: UUID
    connector_key: str
    workspace_id: UUID
    project_id: Optional[UUID] = None
    name: str
    status: str
    scopes: list[str] = Field(default_factory=list)
    config: Optional[dict[str, Any]] = None
    secrets_configured: list[str] = Field(default_factory=list)
    permissions: list[ConnectorPermissionResponse] = Field(default_factory=list)
    created_at: datetime
    updated_at: datetime
