"""Business-rule validators for the Follow domain.

Each validator is a single-purpose class that can be used standalone or
composed into a :class:`ValidatorPipeline` for multi-field validation.
"""
from __future__ import annotations

from repo_core.base.validators import BaseValidator, ValidationError, ValidatorPipeline
from repo_core.domains.follow.model import FollowTargetType

# Auto-synced set of allowed values — any change to the Enum is reflected here.
_VALID_TARGET_TYPES = {t.value for t in FollowTargetType}


class FollowTargetTypeValidator(BaseValidator):
    """Reject any ``target_type`` outside the known Enum choices.

    Usage::

        validator = FollowTargetTypeValidator()
        clean = await validator.validate("story")    # "story"
        clean = await validator.validate("  PERSON  ")  # "person"
    """

    async def validate(self, data: str) -> str:
        value = data.strip().lower() if isinstance(data, str) else data
        if value not in _VALID_TARGET_TYPES:
            raise ValidationError(
                f"target_type must be one of {sorted(_VALID_TARGET_TYPES)}, got '{value}'.",
                field="target_type",
            )
        return value


class TargetIdValidator(BaseValidator):
    """Reject blank or overly-long ``target_id`` values.

    Usage::

        validator = TargetIdValidator(max_length=128)
        clean = await validator.validate("  abc-123  ")  # "abc-123"
    """

    def __init__(self, max_length: int = 128) -> None:
        self._max = max_length

    async def validate(self, data: str) -> str:
        value = data.strip() if isinstance(data, str) else data
        if not value:
            raise ValidationError(
                "target_id cannot be blank.", field="target_id")
        if len(value) > self._max:
            raise ValidationError(
                f"target_id must be at most {self._max} characters, got {len(value)}.",
                field="target_id",
            )
        return value


def build_follow_pipeline() -> ValidatorPipeline:
    """Return a two-step pipeline: validates target_type then target_id.

    Usage::

        pipeline = build_follow_pipeline()
        type_v, id_v = pipeline.validators
        clean_type = await type_v.validate(raw_type)
        clean_id = await id_v.validate(raw_id)
    """
    return ValidatorPipeline(FollowTargetTypeValidator(), TargetIdValidator())
