"""Page-level operations on a source PDF.

`slice_page` writes one page out as its own one-page PDF. `render_page`
rasterizes one page to a PNG. `render_region` rasterizes one rectangle of a page.
All three address pages 1-based, the numbering the document artifacts and the CLI
use.

Single-page work has two callers that pay per page: an ADE submission bills by
the page submitted, so a one-page slice bills one page's credits instead of the
whole document's, and a vision agent looking at one page needs that page and no
other.

A region is rendered when an element's picture has to be re-cut because its
boundary moved: the document model stores a bitmap of each detected picture, and
a bitmap of the old boundary would depict something the element no longer is.
"""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, Tuple

import fitz

if TYPE_CHECKING:
    from PIL.Image import Image

#: A normalized rectangle on a page: 0..1 with the page's top-left as origin,
#: ordered (left, top, right, bottom).
NormBox = Tuple[float, float, float, float]


def slice_page(pdf: Path, page: int, dest: Path) -> Path:
    """Write the single 1-based `page` of `pdf` to `dest` and return it."""
    with fitz.open(str(pdf)) as src:
        if not 1 <= page <= src.page_count:
            raise ValueError(f"page {page} out of range: {pdf.name} has {src.page_count} pages")
        with fitz.open() as sliced:
            sliced.insert_pdf(src, from_page=page - 1, to_page=page - 1)
            sliced.save(str(dest))
    return dest


def render_page(pdf: Path, page: int, dpi: int, dest: Path) -> Tuple[Path, float, float]:
    """Rasterize the 1-based `page` of `pdf` to `dest`; return it with the page size.

    The size is the page's width and height in PDF points, so a caller can map a
    normalized box back onto the source page.
    """
    with fitz.open(str(pdf)) as doc:
        if not 1 <= page <= doc.page_count:
            raise ValueError(f"page {page} out of range: {pdf.name} has {doc.page_count} pages")
        pg = doc[page - 1]
        width, height = pg.rect.width, pg.rect.height
        pg.get_pixmap(dpi=dpi).save(str(dest))
    return dest, width, height


def render_region(pdf: Path, page: int, box: NormBox, dpi: int) -> "Image":
    """Rasterize the rectangle `box` of the 1-based `page` of `pdf` at `dpi`.

    The box is normalized against the page's own rectangle rather than assumed to
    start at the origin, so a page whose media box is offset crops correctly.
    """
    from PIL import Image as PILImage

    with fitz.open(str(pdf)) as doc:
        if not 1 <= page <= doc.page_count:
            raise ValueError(f"page {page} out of range: {pdf.name} has {doc.page_count} pages")
        pg = doc[page - 1]
        rect = pg.rect
        left, top, right, bottom = box
        clip = fitz.Rect(
            rect.x0 + min(left, right) * rect.width,
            rect.y0 + min(top, bottom) * rect.height,
            rect.x0 + max(left, right) * rect.width,
            rect.y0 + max(top, bottom) * rect.height,
        )
        pix = pg.get_pixmap(clip=clip, dpi=dpi)
        return PILImage.frombytes("RGB", (pix.width, pix.height), pix.samples)
