"""
PDF image operations.

This module provides extraction and manipulation of images embedded in PDF
documents, including conversion to RGBA pixel data.

Example usage:
    from micropdf.image_ops import PdfImage

    image = PdfImage.from_dict(dict_handle, raw_data)
    print(f"Size: {image.width}x{image.height}")
    rgba_data = image.to_rgba()
    image.drop()
"""

from .ffi_native import ffi, lib, is_native_available
from .errors import MicroPDFError, ErrorCode


def _check_native() -> None:
    if not is_native_available():
        raise MicroPDFError(ErrorCode.SYSTEM, "Native library not available.")


class PdfImage:
    """A PDF image extracted from a PDF image dictionary."""

    __slots__ = ('_handle',)

    def __init__(self, handle: int) -> None:
        self._handle = handle

    @classmethod
    def from_dict(cls, dict_ptr: int, data: bytes) -> 'PdfImage':
        """
        Create a PdfImage from a PDF dictionary handle and raw image data.

        Args:
            dict_ptr: Handle to a PDF image dictionary object.
            data: Raw image data bytes.

        Returns:
            PdfImage instance.

        Raises:
            MicroPDFError: If the image cannot be loaded.
        """
        _check_native()
        handle = lib.mp_pdf_image_from_dict(dict_ptr, data, len(data))
        if handle == 0:
            raise MicroPDFError(ErrorCode.GENERIC, "Failed to load image from dictionary")
        return cls(handle)

    @property
    def width(self) -> int:
        """Get the image width in pixels."""
        return lib.mp_pdf_image_width(self._handle)

    @property
    def height(self) -> int:
        """Get the image height in pixels."""
        return lib.mp_pdf_image_height(self._handle)

    def to_rgba(self) -> bytes:
        """
        Convert the image to RGBA pixel data.

        Returns:
            RGBA pixel data as bytes (4 bytes per pixel).

        Raises:
            MicroPDFError: If conversion fails.
        """
        buf_len = self.width * self.height * 4
        out_buf = ffi.new(f"unsigned char[{buf_len}]")
        result = lib.mp_pdf_image_to_rgba(self._handle, out_buf, buf_len)
        if result < 0:
            raise MicroPDFError(
                ErrorCode.GENERIC, f"Failed to convert image to RGBA: error code {result}"
            )
        return bytes(ffi.buffer(out_buf, buf_len))

    def drop(self) -> None:
        """Release the image resources."""
        if getattr(self, '_handle', 0) != 0:
            lib.mp_pdf_image_free(self._handle)
            self._handle = 0

    def __del__(self) -> None:
        try:
            self.drop()
        except Exception:
            pass

    def __enter__(self) -> 'PdfImage':
        return self

    def __exit__(self, *args: object) -> None:
        self.drop()


__all__ = ["PdfImage"]
