"""按像素矩形裁剪栅格图（输出 PNG）。"""

from __future__ import annotations

from pathlib import Path
from typing import Any, Callable


def crop_raster_image(
    input_path: Path,
    output_png: Path,
    *,
    left: int,
    top: int,
    width: int,
    height: int,
    policy_check: Callable[[Path], None],
    bbox_reference_width: int | None = None,
    bbox_reference_height: int | None = None,
) -> dict[str, Any]:
    """
    ``left/top/width/height`` 默认相对于 **input_path** 的像素。

    若 bbox 来自 **vision_analyze_image** 等在 **缩小后的图**（``sent_width``×``sent_height``）上描述的坐标，
    设 ``bbox_reference_width`` = ``sent_width``、``bbox_reference_height`` = ``sent_height``，
    则会按比例映射到 **原图** 再裁剪（插入 Word 前应使用原图路径 + 此参数，勿对缩小图裁剪后当终稿）。
    """
    from PIL import Image

    inp = input_path.expanduser().resolve()
    outp = output_png.expanduser().resolve()
    policy_check(inp)
    policy_check(outp)
    if not inp.is_file():
        return {"ok": False, "error": f"input not found: {inp}"}
    if outp.suffix.lower() != ".png":
        return {"ok": False, "error": "output_path must end with .png"}
    if width <= 0 or height <= 0:
        return {"ok": False, "error": "width and height must be positive"}

    with Image.open(inp) as im:
        W, H = im.size
        rw = bbox_reference_width
        rh = bbox_reference_height
        if rw is not None and rh is not None and rw > 0 and rh > 0:
            sx = W / float(rw)
            sy = H / float(rh)
            left = int(round(left * sx))
            top = int(round(top * sy))
            width = max(1, int(round(width * sx)))
            height = max(1, int(round(height * sy)))
        left = max(0, min(left, max(0, W - 1)))
        top = max(0, min(top, max(0, H - 1)))
        width = min(width, W - left)
        height = min(height, H - top)
        if width <= 0 or height <= 0:
            return {
                "ok": False,
                "error": f"crop box empty after clamp: image {W}x{H}",
            }
        box = (left, top, left + width, top + height)
        cropped = im.crop(box)
        outp.parent.mkdir(parents=True, exist_ok=True)
        cropped.save(outp, format="PNG")

    return {
        "ok": True,
        "path": str(outp),
        "source": str(inp),
        "crop": {"left": left, "top": top, "width": width, "height": height},
    }
