"""
PDF font information and text decoding.

This module provides access to font metrics and text decoding from PDF
font dictionaries, useful for advanced text extraction and layout analysis.

Example usage:
    from micropdf.font_info import PdfFont

    font = PdfFont.from_dict(dict_handle)
    width = font.glyph_width(ord('A'))
    font.drop()
"""

from .ffi_native import 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 PdfFont:
    """A PDF font extracted from a font dictionary."""

    __slots__ = ('_handle',)

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

    @classmethod
    def from_dict(cls, dict_ptr: int) -> 'PdfFont':
        """
        Create a PdfFont from a PDF dictionary handle.

        Args:
            dict_ptr: Handle to a PDF font dictionary object.

        Returns:
            PdfFont instance.

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

    def glyph_width(self, char_code: int) -> float:
        """
        Get the width of a glyph by character code.

        Args:
            char_code: Unicode code point or character code.

        Returns:
            Glyph width in font units.
        """
        return lib.mp_pdf_font_glyph_width(self._handle, char_code)

    def decode_text(self, data: bytes) -> bytes:
        """
        Decode encoded text bytes using this font's encoding.

        Args:
            data: Encoded text bytes from the PDF.

        Returns:
            Decoded text as bytes.

        Raises:
            MicroPDFError: If decoding fails.
        """
        out_buf = bytearray(len(data) * 4)
        result = lib.mp_pdf_font_decode_text(
            self._handle, data, len(data), out_buf, len(out_buf)
        )
        if result < 0:
            raise MicroPDFError(ErrorCode.GENERIC, f"Failed to decode text: error code {result}")
        return bytes(out_buf[:result])

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

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

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

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


__all__ = ["PdfFont"]
