# @File: backend/schemas/whatsapp_automation.py
# @Desc: Pydantic I/O models for WhatsApp campaigns and workflow automation.
#        Kept intentionally minimal — we only expose the fields the
#        client-area console needs. Timestamps are ISO strings.
from __future__ import annotations

from datetime import datetime
from typing import Any, List, Optional

from pydantic import BaseModel, ConfigDict, Field


# ---------------------------------------------------------------------------
# Campaigns
# ---------------------------------------------------------------------------


class CampaignRecipientIn(BaseModel):
    """One recipient row in a campaign create/import payload."""

    phone_number: str = Field(..., min_length=5, max_length=40)
    contact_id: Optional[int] = None


class CampaignCreate(BaseModel):
    """Create or update the draft of a campaign."""

    name: str = Field(..., min_length=1, max_length=128)
    message_body: str = Field(..., min_length=1, max_length=4096)
    media_url: Optional[str] = Field(None, max_length=2048)
    scheduled_at: Optional[datetime] = None
    throttle_per_minute: int = Field(30, ge=1, le=240)
    recipients: List[CampaignRecipientIn] = Field(default_factory=list)


class CampaignUpdate(BaseModel):
    """Patch an existing draft campaign."""

    name: Optional[str] = Field(None, min_length=1, max_length=128)
    message_body: Optional[str] = Field(None, min_length=1, max_length=4096)
    media_url: Optional[str] = Field(None, max_length=2048)
    scheduled_at: Optional[datetime] = None
    throttle_per_minute: Optional[int] = Field(None, ge=1, le=240)
    recipients: Optional[List[CampaignRecipientIn]] = None


class CampaignRecipientOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    phone_number: str
    contact_id: Optional[int]
    status: str
    error_detail: Optional[str]
    sent_at: Optional[datetime]


class CampaignOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    name: str
    message_body: str
    media_url: Optional[str]
    status: str
    scheduled_at: Optional[datetime]
    started_at: Optional[datetime]
    completed_at: Optional[datetime]
    total_recipients: int
    sent_count: int
    delivered_count: int
    replied_count: int
    failed_count: int
    throttle_per_minute: int
    last_error: Optional[str]
    created_at: datetime
    updated_at: datetime


# ---------------------------------------------------------------------------
# Workflows
# ---------------------------------------------------------------------------


class WorkflowTrigger(BaseModel):
    """A single trigger descriptor stored in ``trigger_json``.

    The ``type`` field is validated against a small enum of supported
    triggers; extra keys like ``keyword`` / ``minutes`` / ``campaign_id`` are
    accepted for the trigger types that need them, but we don't enforce
    per-type required fields here — the service layer coerces defaults and
    ignores unknown keys so the UI can evolve without breaking old rows.
    """

    type: str = Field(..., description="new_message | keyword | first_message | outside_hours | no_reply_after | added_to_campaign")
    keyword: Optional[str] = None
    minutes: Optional[int] = Field(None, ge=1, le=10_080)  # up to a week
    campaign_id: Optional[int] = None


class WorkflowAction(BaseModel):
    """A single action descriptor stored in ``actions_json``.

    Supported types: ``send_message``, ``assign_tag``, ``mark_lead``,
    ``notify_admin``. The service layer treats each row as an opaque
    instruction — unknown types are logged and skipped, so a UI that adds a
    new action type never crashes older backends.
    """

    type: str = Field(..., description="send_message | assign_tag | mark_lead | notify_admin")
    body: Optional[str] = Field(None, max_length=4096)
    tag: Optional[str] = Field(None, max_length=64)
    note: Optional[str] = Field(None, max_length=512)


class WorkflowCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=128)
    description: Optional[str] = Field(None, max_length=1024)
    is_active: bool = True
    trigger: WorkflowTrigger
    actions: List[WorkflowAction] = Field(default_factory=list)


class WorkflowUpdate(BaseModel):
    name: Optional[str] = Field(None, min_length=1, max_length=128)
    description: Optional[str] = Field(None, max_length=1024)
    is_active: Optional[bool] = None
    trigger: Optional[WorkflowTrigger] = None
    actions: Optional[List[WorkflowAction]] = None


class WorkflowOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    name: str
    description: Optional[str]
    is_active: bool
    trigger: WorkflowTrigger
    actions: List[WorkflowAction]
    last_run_at: Optional[datetime]
    run_count: int
    created_at: datetime
    updated_at: datetime


class WorkflowRunOut(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    workflow_id: int
    trigger_detail: Optional[str]
    result: str
    error_detail: Optional[str]
    executed_actions: int
    created_at: datetime


class WorkflowTestRequest(BaseModel):
    """Dry-run a workflow against a sample event without sending anything."""

    sample_message: Optional[str] = Field(None, max_length=2048)
    context: Optional[dict[str, Any]] = None