"""Validator for Image DataEntry using Pillow."""

from pathlib import Path
from typing import Any

from PIL import Image

from axm.catalog.entries import DataEntry
from axm.core import BaseValidator, Severity, ValidationError, ValidationResult


class ImageValidator(BaseValidator):
    """Validates image data (list of file paths) against Image DataEntry schema."""

    def __init__(self, entry: DataEntry) -> None:
        """Initialize validator with data entry definition."""
        self.entry = entry

    def validate(self, data: Any) -> ValidationResult:
        """Validate image data (list of file paths)."""
        errors: list[ValidationError] = []

        # 1. Check input type
        if not isinstance(data, list):
            return ValidationResult(
                is_valid=False,
                errors=[
                    ValidationError(
                        field="input",
                        message=(
                            f"Expected list of file paths for IMAGE format, "
                            f"got {type(data)}"
                        ),
                        severity=Severity.ERROR,
                    )
                ],
            )

        # 2. Get expectations
        # Handle both dict spec (DataEntry) and Pydantic model spec (ImageEntry)
        spec = self.entry.data_schema.spec

        # Helper to get attr or dict item
        def get_val(obj: Any, key: str) -> Any:
            return getattr(obj, key) if hasattr(obj, key) else obj.get(key)

        expected_encoding = get_val(spec, "encoding")
        expected_width = get_val(spec, "width")
        expected_height = get_val(spec, "height")

        suffix = f".{expected_encoding.lower()}" if expected_encoding else None

        for path_str in data:
            path = Path(path_str)

            # Extension check
            if suffix and not path.suffix.lower() == suffix:
                errors.append(
                    ValidationError(
                        field=f"file[{path_str}]",
                        message=(
                            f"Extension mismatch: expected {expected_encoding}, "
                            f"got {path.suffix}"
                        ),
                        severity=Severity.ERROR,
                    )
                )

            # Resolution check
            if expected_width or expected_height:
                try:
                    with Image.open(path) as img:
                        width, height = img.size
                        if expected_width and width != expected_width:
                            errors.append(
                                ValidationError(
                                    field=f"file[{path_str}].width",
                                    message=(
                                        f"Resolution mismatch: "
                                        f"expected width {expected_width}, "
                                        f"got {width}"
                                    ),
                                    severity=Severity.ERROR,
                                )
                            )
                        if expected_height and height != expected_height:
                            errors.append(
                                ValidationError(
                                    field=f"file[{path_str}].height",
                                    message=(
                                        f"Resolution mismatch: "
                                        f"expected height {expected_height}, "
                                        f"got {height}"
                                    ),
                                    severity=Severity.ERROR,
                                )
                            )
                except Exception as e:
                    # Could happen if file not found or not an image
                    errors.append(
                        ValidationError(
                            field=f"file[{path_str}]",
                            message=f"Failed to open image for validation: {e}",
                            severity=Severity.ERROR,
                        )
                    )

        return ValidationResult(is_valid=len(errors) == 0, errors=errors)
