#!/usr/bin/env python3
"""Marketplace pack for product shots: centre the product (from transparency or a plain background), pad it to each
marketplace's spec, check fill and pure-white rules, and write a contact sheet.

Presets (W x H, background, product fill target):
  amazon     2000x2000, pure white #FFFFFF, product fills ~85%  (main image rule)
  shopify    2048x2048, white, ~80%
  etsy       2700x2025 (4:3), keep / white, ~75%
  instagram  1080x1350 (4:5), keep, ~70%
  square     1080x1080, keep, ~75%
  story      1080x1920, keep, ~60%

Examples
  python pack.py --inputs https://.../shot1.png https://.../shot2.png --presets amazon,shopify,instagram
  python pack.py --inputs ./shots --presets etsy --bg "#F4F1EA"
"""
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).resolve().parent))
import kmedia as K  # noqa: E402

PRESETS = {
    "amazon": (2000, 2000, "#FFFFFF", 0.85), "shopify": (2048, 2048, "#FFFFFF", 0.80), "etsy": (2700, 2025, "keep", 0.75),
    "instagram": (1080, 1350, "keep", 0.70), "square": (1080, 1080, "keep", 0.75), "story": (1080, 1920, "keep", 0.60),
}


def product_box(img, tol: int = 18):
    """Bounding box of the product: alpha if present, else pixels that differ from the corner colour."""
    from PIL import Image, ImageChops
    if img.mode == "RGBA" and img.getchannel("A").getextrema()[0] < 250:
        return img.getchannel("A").point(lambda a: 255 if a > 16 else 0).getbbox(), "alpha"
    rgb = img.convert("RGB")
    corners = [rgb.getpixel(p) for p in ((0, 0), (rgb.width - 1, 0), (0, rgb.height - 1), (rgb.width - 1, rgb.height - 1))]
    bgc = tuple(sorted(c[k] for c in corners)[1] for k in range(3))
    diff = ImageChops.difference(rgb, Image.new("RGB", rgb.size, bgc)).convert("L").point(lambda v: 255 if v > tol else 0)
    return diff.getbbox(), f"background {K.rgb_hex(bgc)}"


def main() -> None:
    ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    ap.add_argument("--inputs", nargs="+", required=True, help="image URLs / files / a folder")
    ap.add_argument("--presets", default="amazon,instagram")
    ap.add_argument("--bg", default="", help="override background: #RRGGBB or 'keep' (scene shots)")
    ap.add_argument("--fill", type=float, default=0.0, help="override product fill 0..1")
    ap.add_argument("--name", default="product")
    ap.add_argument("--out-dir", default="kenerate-out/product-photoshoot-batch")
    a = ap.parse_args()

    srcs = []
    for s in a.inputs:
        p = Path(s)
        if not K.is_url(s) and p.is_dir():
            srcs += sorted(str(x) for x in p.iterdir() if x.suffix.lower() in K.IMAGE_EXT)
        else:
            srcs.append(s)
    presets = [x.strip() for x in a.presets.split(",") if x.strip()]
    bad = [p for p in presets if p not in PRESETS]
    if bad:
        K.fail(f"Unknown preset(s): {', '.join(bad)}", "Use: " + ", ".join(PRESETS))
    st = K.Status(3, "product-photoshoot-batch")
    K.require(ffmpeg=False, status=st)
    tmp = K.workdir()
    out = Path(a.out_dir)
    out.mkdir(parents=True, exist_ok=True)

    st.step(f"Fetching {len(srcs)} image(s)")
    files = K.fetch_all(srcs, tmp, st, prefix="shot")

    st.step(f"Packing {len(files)} x {len(presets)} preset(s)")
    from PIL import Image
    rows, made = [], []
    total = len(files) * len(presets)
    k = 0
    for i, f in enumerate(files, 1):
        img = K.open_image(f)
        box, how = product_box(img)
        if not box:
            st.warn(f"{f.name}: no product found (blank image?) - skipped")
            continue
        area = (box[2] - box[0]) * (box[3] - box[1]) / (img.width * img.height)
        if how != "alpha" and area > 0.9:
            st.warn(f"{f.name}: no plain background around the product - white-background presets will show the whole "
                    "photo. Cut it out first (Kenerate remove_background, mode cutout) and pass the PNG.")
        for pr in presets:
            W, H, bgspec, fill = PRESETS[pr]
            bgspec = a.bg or bgspec
            fill = a.fill or fill
            if bgspec == "keep" and not (img.mode == "RGBA" and how == "alpha"):
                canvas = K.contain(img.convert("RGB"), W, H, blur_bg=True)
                note = "scene kept (blurred fill for the extra space)"
            else:
                col = K.hex_rgb("#FFFFFF" if bgspec == "keep" else bgspec)
                prod = img.crop(box)
                if prod.mode != "RGBA":
                    prod = prod.convert("RGBA")
                s = min(W * fill / prod.width, H * fill / prod.height)
                prod = prod.resize((max(1, int(prod.width * s)), max(1, int(prod.height * s))), Image.LANCZOS)
                canvas = Image.new("RGBA", (W, H), col + (255,))
                canvas.alpha_composite(prod, ((W - prod.width) // 2, (H - prod.height) // 2))
                note = f"product centred on {K.rgb_hex(col)} ({how})"
            k += 1
            dst = out / pr / f"{K.safe_name(a.name)}_{i:02d}_{pr}.jpg"
            dst.parent.mkdir(parents=True, exist_ok=True)
            rgb = canvas.convert("RGB")
            rgb.save(dst, quality=94)
            pb, _ = product_box(rgb)
            fill_real = round(max((pb[2] - pb[0]) / W, (pb[3] - pb[1]) / H), 3) if pb else 0
            corners_white = all(rgb.getpixel(p) == (255, 255, 255) for p in ((0, 0), (W - 1, 0), (0, H - 1), (W - 1, H - 1)))
            checks = {}
            if pr == "amazon":
                checks = {"pure_white_background": corners_white, "fill_85pct": fill_real >= 0.84}
            rows.append({"file": str(dst.resolve()), "source": f.name, "preset": pr, "size": f"{W}x{H}", "fill": fill_real,
                         "note": note, **({"checks": checks} if checks else {})})
            made.append(dst)
            st.progress(k * 100 / total, dst.name)
            if checks and not all(checks.values()):
                st.warn(f"{dst.name}: Amazon main-image check failed {checks} - cut the product out first (remove_background)")

    st.step("Contact sheet + report")
    sheet = K.contact_sheet(made, out / f"{K.safe_name(a.name)}_sheet.jpg", cols=min(len(presets), 4) or 1, cell=300,
                            labels=[f"{r['preset']} {r['fill']:.0%}" for r in rows])
    (out / f"{K.safe_name(a.name)}_report.json").write_text(json.dumps(rows, indent=2), encoding="utf-8")
    K.finish({"images": rows, "sheet": str(sheet.resolve()), "elapsed_s": st.elapsed()})


if __name__ == "__main__":
    K.main_guard(main)
