"""Pydantic schemas for desktop automation workflows."""

from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, Field, model_validator


class DesktopHealthResponse(BaseModel):
    """Health response for desktop automation integration."""

    status: str = "ok"
    service: str = "desktop_automation"
    backend: str = "mcp_macos_desktop"


class ActionEnvelopeError(BaseModel):
    """Structured error content aligned with MCP action envelopes."""

    code: str | None = None
    message: str | None = None
    details: dict[str, Any] = Field(default_factory=dict)


class DesktopActionResponse(BaseModel):
    """Generic desktop action response aligned with the shared action envelope."""

    ok: bool = True
    action: str
    timestamp: str | None = None
    data: dict[str, Any] = Field(default_factory=dict)
    artifacts: dict[str, Any] = Field(default_factory=dict)
    error: ActionEnvelopeError | None = None

    @classmethod
    def from_adapter_result(cls, result: dict[str, Any]) -> DesktopActionResponse:
        """Build a response model from adapter/service result dictionaries."""
        return cls(
            ok=bool(result.get("ok", True)),
            action=str(result.get("action", "desktop_action")),
            timestamp=result.get("timestamp"),
            data=result.get("data") or {},
            artifacts=result.get("artifacts") or {},
            error=result.get("error"),
        )


class ScreenRegion(BaseModel):
    """Optional rectangular region for screen operations."""

    x: int = Field(..., ge=0)
    y: int = Field(..., ge=0)
    width: int = Field(..., gt=0)
    height: int = Field(..., gt=0)


class ZaloSendRequest(BaseModel):
    """Request to send a message via Zalo desktop automation."""

    target_type: Literal["contact", "my_document"]
    target_name: str | None = Field(
        default=None, description="Required when target_type=contact."
    )
    message: str = Field(..., min_length=1)
    verify_before_send: bool = True
    press_enter: bool = True
    capture_evidence: bool = True
    message_label: str | None = Field(
        default=None, description="Optional business label for logs."
    )
    workflow_id: str | None = Field(
        default=None, description="Optional caller-defined trace identifier."
    )

    @model_validator(mode="after")
    def validate_target_name(self) -> ZaloSendRequest:
        """Require a contact name when targeting a contact chat."""
        if self.target_type == "contact" and not self.target_name:
            raise ValueError("target_name is required when target_type='contact'.")
        return self


class ZaloVerifyChatRequest(BaseModel):
    """Request to verify the currently active Zalo chat."""

    target_name: str = Field(..., min_length=1)
    allow_partial_match: bool = True
    capture_evidence: bool = True
    use_screen_ocr: bool = False
    region: ScreenRegion | None = None


class ZaloDownloadLatestFileRequest(BaseModel):
    """Request to download the latest file from a Zalo chat to a project folder."""

    target_name: str = Field(..., min_length=1)
    project_code: str = Field(..., min_length=1)
    project_path: str = Field(..., min_length=1)
    subfolder: str = Field(default="incoming/zalo")
    download_dir: str = Field(default="/Users/pain/Downloads")
    rename_to: str | None = None
    timeout_seconds: float = Field(default=60.0, gt=0)
    allow_partial_match: bool = True
    verify_before_download: bool = True
    capture_evidence: bool = True
    workflow_id: str | None = Field(
        default=None, description="Optional caller-defined trace identifier."
    )


class DesktopPressKeysRequest(BaseModel):
    """Request for pressing one or more keys through the desktop adapter."""

    keys: list[str] = Field(..., min_length=1)
    app_name: str | None = None
    bundle_id: str | None = None
    target_description: str | None = None
    capture_evidence: bool = False


class DesktopTypeTextRequest(BaseModel):
    """Request for typing text into the active desktop control."""

    text: str = Field(..., min_length=1)
    app_name: str | None = None
    bundle_id: str | None = None
    clear_first: bool = False
    press_enter: bool = False
    target_description: str | None = None
    capture_evidence: bool = False


class ScreenReadTextRequest(BaseModel):
    """Request for OCR-style text extraction from the current screen or region."""

    region: ScreenRegion | None = None
    expected_contains: str | None = None
    language_hint: str | None = Field(
        default=None, description="Future OCR language hint."
    )
    capture_screenshot_first: bool = True
    include_artifacts: bool = True


class ZaloSendWorkflowRequest(BaseModel):
    """High-level send workflow contract for service-layer orchestration."""

    target_type: Literal["contact", "my_document"]
    target_name: str | None = None
    message: str = Field(..., min_length=1)
    verify_before_send: bool = True
    press_enter: bool = True
    capture_evidence: bool = True
    workflow_id: str | None = None

    @model_validator(mode="after")
    def validate_target_name(self) -> ZaloSendWorkflowRequest:
        """Require a contact name when targeting a contact chat."""
        if self.target_type == "contact" and not self.target_name:
            raise ValueError("target_name is required when target_type='contact'.")
        return self


class ZaloIncomingFileWorkflowRequest(BaseModel):
    """High-level contract for verified file collection from a Zalo chat."""

    target_name: str = Field(..., min_length=1)
    project_code: str = Field(..., min_length=1)
    project_path: str = Field(..., min_length=1)
    subfolder: str = Field(default="incoming/zalo")
    download_dir: str = Field(default="/Users/pain/Downloads")
    rename_to: str | None = None
    timeout_seconds: float = Field(default=60.0, gt=0)
    allow_partial_match: bool = True
    verify_before_download: bool = True
    capture_evidence: bool = True
    workflow_id: str | None = None
