"""
Data Sync WebSocket message schemas (PowerSync).

Provides typed messages for real-time data synchronization including:
- Subscribe/unsubscribe to entity changes
- Create/update/delete notifications
- Conflict detection and resolution
- Checkpoint management for resumable sync

Usage:
    from lightwave.schema.pydantic.contracts.websockets.sync import (
        SyncSubscribeInbound,
        SyncUpdateOutbound,
        SyncConflictOutbound,
    )

    # Client subscribes to changes
    sub = SyncSubscribeInbound.model_validate(raw_data)

    # Server sends update
    update = SyncUpdateOutbound(
        entity_type="CallSheet",
        entity_id="cs-123",
        operation="update",
        data={"title": "Day 1 - Updated"},
        version=5,
    )
    await websocket.send(update.to_ws_json())
"""

from datetime import datetime
from typing import Any, Literal

from pydantic import Field

from lightwave.schema.pydantic.contracts.websockets.base import WSMessage

# =============================================================================
# Enums
# =============================================================================

SyncOperation = Literal["create", "update", "upsert", "delete"]
SyncConflictResolution = Literal["server_wins", "client_wins", "merge", "manual"]


# =============================================================================
# Inbound Messages (Client -> Server)
# =============================================================================


class SyncSubscribeInbound(WSMessage):
    """
    Subscribe to entity changes.

    Client sends this to start receiving updates for specific entity types.
    """

    type: Literal["sync.subscribe"] = "sync.subscribe"
    entity_types: list[str] = Field(
        ...,
        min_length=1,
        description="Entity types to subscribe to",
    )
    team_id: str | None = Field(
        None,
        description="Filter to specific team",
    )
    filters: dict[str, Any] | None = Field(
        None,
        description="Additional filters (e.g., {'status': 'active'})",
    )
    include_initial: bool = Field(
        False,
        description="Whether to send current state on subscribe",
    )


class SyncUnsubscribeInbound(WSMessage):
    """
    Unsubscribe from entity changes.

    Client sends this to stop receiving updates.
    """

    type: Literal["sync.unsubscribe"] = "sync.unsubscribe"
    entity_types: list[str] | None = Field(
        None,
        description="Entity types to unsubscribe from (null = all)",
    )
    team_id: str | None = Field(None, description="Team to unsubscribe from")


class SyncAckInbound(WSMessage):
    """
    Acknowledge receipt of sync message.

    Client sends this to confirm processing of update/delete.
    """

    type: Literal["sync.ack"] = "sync.ack"
    message_ids: list[str] = Field(
        ...,
        description="IDs of messages being acknowledged",
    )
    checkpoint: str | None = Field(
        None,
        description="Checkpoint to save (for resumable sync)",
    )


class SyncCheckpointInbound(WSMessage):
    """
    Client checkpoint for resumable sync.

    Sent periodically or on disconnect to enable resume from last position.
    """

    type: Literal["sync.checkpoint"] = "sync.checkpoint"
    checkpoint_id: str = Field(..., description="Checkpoint identifier")
    last_sync_timestamp: datetime = Field(
        ...,
        description="Timestamp of last processed message",
    )
    entity_versions: dict[str, int] | None = Field(
        None,
        description="Last known version per entity type",
    )


# =============================================================================
# Outbound Messages (Server -> Client)
# =============================================================================


class SyncUpdateOutbound(WSMessage):
    """
    Entity was created or updated.

    Sent when an entity changes that the client is subscribed to.
    """

    type: Literal["sync.update"] = "sync.update"
    entity_type: str = Field(..., description="Type of entity")
    entity_id: str = Field(..., description="Entity identifier")
    operation: SyncOperation = Field(..., description="Operation type")
    data: dict[str, Any] = Field(..., description="Entity data")
    version: int = Field(..., ge=1, description="Entity version number")
    changed_fields: list[str] | None = Field(
        None,
        description="Fields that changed (for partial updates)",
    )
    changed_by: str | None = Field(None, description="User who made the change")


class SyncDeleteOutbound(WSMessage):
    """
    Entity was deleted.

    Sent when a subscribed entity is deleted.
    """

    type: Literal["sync.delete"] = "sync.delete"
    entity_type: str = Field(..., description="Type of entity")
    entity_id: str = Field(..., description="Entity identifier")
    deleted_by: str | None = Field(None, description="User who deleted")
    soft_delete: bool = Field(True, description="Whether soft or hard delete")


class SyncBatchOutbound(WSMessage):
    """
    Batch of sync updates.

    Used for initial sync or catching up after reconnect.
    """

    type: Literal["sync.batch"] = "sync.batch"
    updates: list[dict[str, Any]] = Field(
        ...,
        description="List of update messages",
    )
    is_initial: bool = Field(
        False,
        description="Whether this is initial sync batch",
    )
    has_more: bool = Field(
        False,
        description="Whether more batches are coming",
    )
    batch_index: int = Field(0, ge=0, description="Batch number")
    total_batches: int | None = Field(None, description="Total batches if known")


class SyncConflictOutbound(WSMessage):
    """
    Sync conflict detected.

    Sent when client's local changes conflict with server state.
    """

    type: Literal["sync.conflict"] = "sync.conflict"
    entity_type: str = Field(..., description="Type of entity")
    entity_id: str = Field(..., description="Entity identifier")
    local_version: int = Field(..., description="Client's version")
    server_version: int = Field(..., description="Server's version")
    local_data: dict[str, Any] = Field(..., description="Client's data")
    server_data: dict[str, Any] = Field(..., description="Server's data")
    conflicting_fields: list[str] = Field(
        default_factory=list,
        description="Fields with conflicts",
    )
    suggested_resolution: SyncConflictResolution | None = Field(
        None,
        description="Suggested resolution strategy",
    )
    auto_resolved: bool = Field(
        False,
        description="Whether conflict was auto-resolved",
    )


class SyncCheckpointAckOutbound(WSMessage):
    """
    Server acknowledges checkpoint.

    Confirms that checkpoint was saved successfully.
    """

    type: Literal["sync.checkpoint_ack"] = "sync.checkpoint_ack"
    checkpoint_id: str = Field(..., description="Checkpoint that was saved")
    saved_at: datetime = Field(..., description="When checkpoint was saved")
    next_checkpoint_after: int = Field(
        30,
        description="Suggested seconds until next checkpoint",
    )
