import argparse
import io
import os
from pathlib import Path
import warnings

from PIL import Image, ImageDraw


MAX_BYTES = 20 * 1024 * 1024
MAX_PIXELS = 16_000_000


def create_mask(source: Path, target: Path, rect: tuple[int, int, int, int]) -> dict:
    if source.resolve() == target.resolve():
        raise ValueError("output must differ from input")
    if target.suffix.lower() != ".png":
        raise ValueError("output must use .png")
    if not target.parent.is_dir() or not os.access(target.parent, os.W_OK):
        raise ValueError("output directory must exist and be writable")
    if target.exists() or target.is_symlink():
        raise ValueError("output already exists; choose a new filename")
    with source.open("rb") as stream:
        raw = stream.read(MAX_BYTES + 1)
    if not raw or len(raw) > MAX_BYTES:
        raise ValueError("input must be nonempty and at most 20 MiB")
    Image.MAX_IMAGE_PIXELS = MAX_PIXELS
    with warnings.catch_warnings():
        warnings.simplefilter("error", Image.DecompressionBombWarning)
        with Image.open(io.BytesIO(raw)) as image:
            if image.format != "PNG" or getattr(image, "n_frames", 1) != 1:
                raise ValueError("input must be a real single-frame PNG")
            width, height = image.size
            if width * height > MAX_PIXELS:
                raise ValueError("input exceeds 16 million pixels")
            image.load()
    x, y, rect_width, rect_height = rect
    if min(x, y) < 0 or min(rect_width, rect_height) <= 0:
        raise ValueError("rectangle requires nonnegative position and positive dimensions")
    if x + rect_width > width or y + rect_height > height:
        raise ValueError("rectangle exceeds the actual input canvas")
    mask = Image.new("RGBA", (width, height), (255, 255, 255, 255))
    ImageDraw.Draw(mask).rectangle(
        (x, y, x + rect_width - 1, y + rect_height - 1),
        fill=(255, 255, 255, 0),
    )
    encoded = io.BytesIO()
    mask.save(encoded, format="PNG")
    with target.open("xb") as output:
        output.write(encoded.getvalue())
    return {"width": width, "height": height, "transparent_rectangle": rect}


def main() -> None:
    parser = argparse.ArgumentParser(description="Create a local PNG edit mask; no API requests.")
    parser.add_argument("--input", type=Path, required=True)
    parser.add_argument("--output", type=Path, required=True)
    parser.add_argument("--rect", type=int, nargs=4, required=True, metavar=("X", "Y", "WIDTH", "HEIGHT"))
    args = parser.parse_args()
    try:
        result = create_mask(args.input, args.output, tuple(args.rect))
    except (OSError, ValueError, Image.DecompressionBombError, Image.DecompressionBombWarning) as error:
        parser.exit(1, f"Mask not created: {error}\n")
    print(f"Created {args.output.name}: {result['width']}x{result['height']}; inspect alpha and alignment before any API request.")


if __name__ == "__main__":
    main()
