"""
WebSocket message models for AiCippy.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from datetime import UTC, datetime
from enum import StrEnum
from typing import Any


class FileOperationType(StrEnum):
    """Types of file operations over WebSocket."""

    UPLOAD = "file_upload"
    DOWNLOAD = "file_download"
    SYNC = "file_sync"
    DELETE = "file_delete"
    LIST = "file_list"


@dataclass(frozen=True)
class FileTransferMessage:
    """Message for file transfer operations."""

    operation: FileOperationType
    file_path: str
    file_name: str
    file_size: int = 0
    chunk_index: int = 0
    total_chunks: int = 0
    data: bytes = b""
    checksum: str = ""

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization."""
        return {
            "operation": self.operation.value,
            "file_path": self.file_path,
            "file_name": self.file_name,
            "file_size": self.file_size,
            "chunk_index": self.chunk_index,
            "total_chunks": self.total_chunks,
            "checksum": self.checksum,
        }


@dataclass
class FileTransferProgress:
    """Progress tracking for file transfers."""

    file_name: str
    total_bytes: int
    transferred_bytes: int = 0
    status: str = "pending"  # pending, transferring, complete, error
    error: str | None = None

    @property
    def progress_pct(self) -> float:
        """Calculate percentage of transfer complete."""
        if self.total_bytes == 0:
            return 0.0
        return min(100.0, self.transferred_bytes / self.total_bytes * 100)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "file_name": self.file_name,
            "total_bytes": self.total_bytes,
            "transferred_bytes": self.transferred_bytes,
            "status": self.status,
            "error": self.error,
            "progress_pct": self.progress_pct,
        }


class MessageType(StrEnum):
    """Types of WebSocket messages."""

    # Client -> Server
    AUTHENTICATE = "authenticate"
    CHAT = "chat"
    TASK = "task"
    COMMAND = "command"
    PING = "ping"

    # Server -> Client
    AUTHENTICATED = "authenticated"
    RESPONSE = "response"
    AGENT_UPDATE = "agent_update"
    TOOL_OUTPUT = "tool_output"
    DIFF = "diff"
    PROGRESS = "progress"
    ERROR = "error"
    PONG = "pong"


@dataclass
class WebSocketMessage:
    """Base WebSocket message structure."""

    type: MessageType
    payload: dict[str, Any] = field(default_factory=dict)
    correlation_id: str | None = None
    tenant_id: str | None = None
    timestamp: datetime = field(default_factory=lambda: datetime.now(UTC))

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization."""
        result: dict[str, Any] = {
            "type": self.type.value,
            "payload": self.payload,
            "correlation_id": self.correlation_id,
            "timestamp": self.timestamp.isoformat(),
        }
        if self.tenant_id is not None:
            result["tenant_id"] = self.tenant_id
        return result

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> WebSocketMessage:
        """Create from dictionary."""
        return cls(
            type=MessageType(data["type"]),
            payload=data.get("payload", {}),
            correlation_id=data.get("correlation_id"),
            tenant_id=data.get("tenant_id"),
            timestamp=datetime.fromisoformat(data["timestamp"])
            if "timestamp" in data
            else datetime.now(UTC),
        )


@dataclass
class AgentUpdate:
    """Agent status update message."""

    agent_id: str
    agent_type: str
    status: str
    progress: int
    message: str = ""
    tokens_used: int = 0

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "agent_id": self.agent_id,
            "agent_type": self.agent_type,
            "status": self.status,
            "progress": self.progress,
            "message": self.message,
            "tokens_used": self.tokens_used,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> AgentUpdate:
        """Create from dictionary."""
        return cls(
            agent_id=data["agent_id"],
            agent_type=data["agent_type"],
            status=data["status"],
            progress=data["progress"],
            message=data.get("message", ""),
            tokens_used=data.get("tokens_used", 0),
        )


@dataclass
class ToolOutput:
    """Tool execution output message."""

    tool_name: str
    output: str
    success: bool
    execution_time_ms: int = 0
    metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "tool_name": self.tool_name,
            "output": self.output,
            "success": self.success,
            "execution_time_ms": self.execution_time_ms,
            "metadata": self.metadata,
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> ToolOutput:
        """Create from dictionary."""
        return cls(
            tool_name=data["tool_name"],
            output=data["output"],
            success=data["success"],
            execution_time_ms=data.get("execution_time_ms", 0),
            metadata=data.get("metadata", {}),
        )


@dataclass
class DiffMessage:
    """File diff message for code changes."""

    file_path: str
    old_content: str
    new_content: str
    diff_type: str = "unified"  # unified, side_by_side
    language: str | None = None

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "file_path": self.file_path,
            "old_content": self.old_content,
            "new_content": self.new_content,
            "diff_type": self.diff_type,
            "language": self.language,
        }


@dataclass
class ProgressMessage:
    """Progress update message."""

    task_id: str
    current: int
    total: int
    message: str = ""
    stage: str | None = None

    @property
    def percentage(self) -> float:
        """Calculate percentage complete."""
        if self.total == 0:
            return 0.0
        return (self.current / self.total) * 100

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary."""
        return {
            "task_id": self.task_id,
            "current": self.current,
            "total": self.total,
            "message": self.message,
            "stage": self.stage,
            "percentage": self.percentage,
        }
