"""Type definitions for ingress recipient SDK.

These types define the contract for data received FROM ingress cores
after processing through the 5-stage pipeline.

IMPORTANT: All field names use snake_case to match backend conventions.
"""

from datetime import datetime
from typing import Any
from uuid import UUID

from pydantic import BaseModel, Field, field_validator


class RecipientMetadata(BaseModel):
    """Metadata about the ingress processing pipeline.

    Contains information about how the data was processed before
    being sent to the recipient service.

    Attributes:
        source_ip: Optional source IP address of the original sender
        ingress_timestamp: When the data was received by the ingress core
        transformations_applied: Optional list of transformation names applied

    Example:
        ```python
        metadata = RecipientMetadata(
            source_ip="192.168.1.100",
            ingress_timestamp=datetime.now(UTC),
            transformations_applied=["normalize", "enrich", "speed_conversion"],
        )
        ```
    """

    source_ip: str | None = Field(None, description="Source IP of original sender")
    ingress_timestamp: datetime = Field(..., description="Ingress receipt timestamp")
    transformations_applied: list[str] | None = Field(
        None, description="Transformations applied by ingress pipeline"
    )


class RecipientData(BaseModel):
    """Data received from ingress core after processing.

    This is the standardized contract that ALL recipients must accept.

    The ingress core processes data through a 5-stage pipeline:
    1. Auth - Validate API key/JWT
    2. Validate - JSON Schema validation
    3. Transform - Field mapping, enrichment
    4. Route - Destination selection
    5. Dispatch - Send to recipients

    IMPORTANT: All field names use snake_case to match backend conventions.

    Attributes:
        channel_id: Channel identifier (e.g., 'ch_maritime_telemetry')
        tenant_id: Tenant UUID
        timestamp: Original data timestamp (from the client, not when ingested)
        data: Arbitrary JSON data payload (potentially transformed)
        metadata: Ingress processing metadata

    Example:
        ```python
        data = RecipientData(
            channel_id="ch_maritime_telemetry",
            tenant_id=UUID("123e4567-e89b-12d3-a456-426614174000"),
            timestamp=datetime.now(UTC),
            data={
                "vessel_id": "v_12345",
                "latitude": 59.9139,
                "longitude": 10.7522,
                "speed": 15.3,
            },
            metadata=RecipientMetadata(
                ingress_timestamp=datetime.now(UTC),
                transformations_applied=["normalize"],
            ),
        )
        ```
    """

    channel_id: str = Field(..., min_length=1, description="Channel identifier")
    tenant_id: UUID = Field(..., description="Tenant UUID")
    timestamp: datetime = Field(..., description="Original data timestamp")
    data: dict[str, Any] = Field(..., description="Arbitrary JSON data")
    metadata: RecipientMetadata = Field(..., description="Ingress metadata")

    @field_validator("channel_id")
    @classmethod
    def validate_channel_id(cls, v: str) -> str:
        """Validate channel_id is not empty or whitespace-only.

        Args:
            v: The channel_id value to validate

        Returns:
            The validated channel_id

        Raises:
            ValueError: If channel_id is empty or whitespace-only
        """
        if not v.strip():
            raise ValueError("channel_id cannot be empty or whitespace-only")
        return v


class RecipientResponse(BaseModel):
    """Response sent back to ingress core after processing.

    Recipients should return this response to indicate whether
    they successfully processed the data or not.

    Attributes:
        status: Processing status ('accepted' or 'rejected')
        message: Optional message with details about the processing result

    Example:
        ```python
        # Success
        response = RecipientResponse(
            status="accepted",
            message="Data processed successfully",
        )

        # Failure
        response = RecipientResponse(
            status="rejected",
            message="Invalid vessel_id: v_12345 not found",
        )
        ```
    """

    status: str = Field(..., pattern="^(accepted|rejected)$", description="Processing status")
    message: str | None = Field(None, description="Optional status message")

    @field_validator("status")
    @classmethod
    def validate_status(cls, v: str) -> str:
        """Validate status is either 'accepted' or 'rejected'.

        Args:
            v: The status value to validate

        Returns:
            The validated status

        Raises:
            ValueError: If status is not 'accepted' or 'rejected'
        """
        if v not in ("accepted", "rejected"):
            raise ValueError("status must be 'accepted' or 'rejected'")
        return v
