"""Crop operation for extracting image regions."""

from typing import Any

import numpy as np
from numpy.typing import NDArray

from axm.operations import OperationProtocol, OperationResult


class CropOperation(OperationProtocol):
    """Crop a rectangular region from an image.

    Config:
        x: Left coordinate (required).
        y: Top coordinate (required).
        width: Crop width (required).
        height: Crop height (required).
    """

    @property
    def name(self) -> str:
        """Operation name."""
        return "image.crop"

    def execute(
        self,
        data: NDArray[np.uint8] | None,
        context: dict[str, Any],
        config: dict[str, Any],
    ) -> OperationResult:
        """Crop image to specified region.

        Args:
            data: Input image array.
            context: Unused.
            config: Must contain x, y, width, height.

        Returns:
            OperationResult with cropped image.
        """
        if data is None:
            return OperationResult(
                data=None,
                success=False,
                error="No input image provided",
            )

        x = config.get("x", 0)
        y = config.get("y", 0)
        width = config.get("width", 0)
        height = config.get("height", 0)

        img_height, img_width = data.shape[:2]

        # Bounds check
        if x + width > img_width or y + height > img_height:
            return OperationResult(
                data=None,
                success=False,
                error=f"Crop region out of bounds. Image: {img_width}x{img_height}, "
                f"Requested: x={x}, y={y}, w={width}, h={height}",
            )

        if x < 0 or y < 0 or width <= 0 or height <= 0:
            return OperationResult(
                data=None,
                success=False,
                error="Invalid crop parameters: all values must be positive",
            )

        cropped: NDArray[Any] = data[y : y + height, x : x + width]

        return OperationResult(
            data=cropped,
            success=True,
            metadata={"width": width, "height": height},
        )
