"""Marketplace input validation.

Reusable validation helpers for listing creation. ``validate_listing_images`` is
designed to be called from a WTForms ``validate_<field>`` method, so it raises
``wtforms.validators.ValidationError`` with a user-friendly message.
"""

from __future__ import annotations

import io

from PIL import Image
from werkzeug.datastructures import FileStorage
from wtforms.validators import ValidationError

from app.marketplace.utils import allowed_image

MIN_IMAGES = 1
MAX_IMAGES = 7
MAX_IMAGE_BYTES = 5 * 1024 * 1024  # 5 MB per image


def _non_empty(files: list[FileStorage]) -> list[FileStorage]:
    """Drop empty file slots (browsers submit a blank FileStorage for none)."""
    return [f for f in files if f and f.filename]


def validate_listing_images(files: list[FileStorage]) -> None:
    """Validate the uploaded listing images.

    Enforces the documented business rule of 1–7 images and verifies each file
    by extension, declared MIME type, size and an actual Pillow decode. The file
    stream is rewound afterwards so it can be saved later.
    """
    real = _non_empty(files)

    if len(real) < MIN_IMAGES:
        raise ValidationError("Please upload at least one image.")
    if len(real) > MAX_IMAGES:
        raise ValidationError(f"A listing may have at most {MAX_IMAGES} images.")

    for file in real:
        if not allowed_image(file.filename):
            raise ValidationError(
                f"'{file.filename}' is not an allowed image type."
            )
        if file.mimetype and not file.mimetype.startswith("image/"):
            raise ValidationError(f"'{file.filename}' is not an image.")

        data = file.read()
        if len(data) > MAX_IMAGE_BYTES:
            raise ValidationError(
                f"'{file.filename}' exceeds the 5 MB per-image limit."
            )
        try:
            Image.open(io.BytesIO(data)).verify()
        except Exception as exc:  # noqa: BLE001
            raise ValidationError(
                f"'{file.filename}' is not a valid image."
            ) from exc
        file.stream.seek(0)  # rewind for the subsequent save
