"""Business-rule validators for Telegram media files."""
from __future__ import annotations

from repo_core.base.validators import BaseValidator, ValidationError, ValidatorPipeline

# Allowed media type values
_VALID_MEDIA_TYPES: frozenset[str] = frozenset({
    "photo",
    "video",
    "document",
    "gif",
    "audio",
    "sticker",
})


class StorageKeyValidator(BaseValidator):
    """Ensure the S3 storage key is a non-empty string with valid format."""

    MAX_LENGTH: int = 1024

    async def validate(self, data: str) -> str:
        if not isinstance(data, str) or not data.strip():
            raise ValidationError(
                "Storage key must be a non-empty string.", field="storage_key"
            )
        if len(data) > self.MAX_LENGTH:
            raise ValidationError(
                f"Storage key must be at most {self.MAX_LENGTH} characters.",
                field="storage_key",
            )
        return data.strip()


class MediaTypeValidator(BaseValidator):
    """Ensure media_type is one of the allowed values."""

    async def validate(self, data: str) -> str:
        if data not in _VALID_MEDIA_TYPES:
            raise ValidationError(
                f"media_type must be one of: {', '.join(sorted(_VALID_MEDIA_TYPES))}.",
                field="media_type",
            )
        return data


class PeerIdValidator(BaseValidator):
    """Ensure peer_id is a positive integer."""

    async def validate(self, data: int) -> int:
        if not isinstance(data, int):
            raise ValidationError(
                "peer_id must be an integer.", field="peer_id"
            )
        if data <= 0:
            raise ValidationError(
                "peer_id must be a positive integer.", field="peer_id"
            )
        return data


class MessageIdValidator(BaseValidator):
    """Ensure message_id is a positive integer."""

    async def validate(self, data: int) -> int:
        if not isinstance(data, int):
            raise ValidationError(
                "message_id must be an integer.", field="message_id"
            )
        if data <= 0:
            raise ValidationError(
                "message_id must be a positive integer.", field="message_id"
            )
        return data


class MediaFilePayloadValidator(BaseValidator):
    """Validate a media file payload dict field-by-field.

    Applies :class:`StorageKeyValidator` and :class:`MediaTypeValidator`
    to their respective keys.
    """

    async def validate(self, data: dict) -> dict:
        if not isinstance(data, dict):
            raise ValidationError(
                "Payload must be a dictionary.", field="payload"
            )

        storage_key = data.get("storage_key", "")
        data["storage_key"] = await StorageKeyValidator().validate(storage_key)

        media_type = data.get("media_type", "")
        data["media_type"] = await MediaTypeValidator().validate(media_type)

        return data


def build_media_file_pipeline() -> ValidatorPipeline:
    """Return a ready-to-use pipeline for media file validation.

    Validates a dict containing ``storage_key`` and ``media_type`` keys.
    """
    return ValidatorPipeline(MediaFilePayloadValidator())
