#!/usr/bin/env python3
"""
AI Room Designer — Stage 1 spike pipeline (LOCAL RIG ONLY, no deploy).

Flow:
  1. prepare  <photo> <mode> <job-dir>   -> writes job.json with the locked
      structure-preserving edit prompt for that mode. The actual image edit is
      executed by whatever image-edit backend is wired in (Stage 1: Muse media
      image-edit pipeline, standing in for the planned Gemini edit route in
      Build Plan v1 — same prompt contract, zero paid API spend).
  2. finish   <job-dir> <after-image>   -> copies the edit into the job dir,
      builds a labelled before/after composite + a wipe-slider-style split
      composite, runs qc_score, writes qc.json.

Usage:
  python3 pipeline.py prepare photo.jpg colors-and-lighting ../tests/test2-living
  python3 pipeline.py finish  ../tests/test2-living /path/to/edited.png
"""
import json
import shutil
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))
from modes import MODES, build_prompt  # noqa: E402
from plan_engine import build_plan  # noqa: E402
from qc_score import score, verdict  # noqa: E402


def _room_from(name):
    for room in ("kitchen", "living", "bedroom"):
        if room in name:
            return room
    return "room"
from PIL import Image, ImageDraw  # noqa: E402


def prepare(photo, mode, job_dir):
    job = Path(job_dir)
    job.mkdir(parents=True, exist_ok=True)
    before = job / "before.jpg"
    Image.open(photo).convert("RGB").save(before, quality=92)
    meta = {
        "mode": mode,
        "mode_label": MODES[mode]["label"],
        "aggression_1_to_5": MODES[mode]["aggression"],
        "prompt": build_prompt(mode),
        "backend_stage1": "muse-media-image-edit (Gemini-route stand-in, $0 API)",
    }
    (job / "job.json").write_text(json.dumps(meta, indent=2))
    print(json.dumps(meta, indent=2))


def _label(img, text):
    bar = Image.new("RGB", (img.width, 36), (1, 30, 73))  # ExM steel blue
    bar_draw = ImageDraw.Draw(bar)
    bar_draw.text((12, 11), text, fill=(255, 255, 255))
    out = Image.new("RGB", (img.width, img.height + 36))
    out.paste(bar, (0, 0))
    out.paste(img, (0, 36))
    return out


def finish(job_dir, after_image):
    job = Path(job_dir)
    meta = json.loads((job / "job.json").read_text())
    after = job / "after.png"
    Image.open(after_image).convert("RGB").save(after)

    before_img = Image.open(job / "before.jpg").convert("RGB")
    after_img = Image.open(after).convert("RGB")
    # Normalise the edit onto the before's frame for a fair composite + scoring.
    after_norm = after_img.resize(before_img.size)
    after_norm.save(job / "after_matched.png")

    side = Image.new("RGB", (before_img.width * 2 + 8, before_img.height + 36))
    side.paste(_label(before_img, "BEFORE"), (0, 0))
    side.paste(_label(after_norm, f"AFTER - {meta['mode_label']}"), (before_img.width + 8, 0))
    side.save(job / "before_after.png")

    # Simulated slider: left half before, right half after, gold divider.
    wipe = before_img.copy()
    half = before_img.width // 2
    wipe.paste(after_norm.crop((half, 0, before_img.width, before_img.height)), (half, 0))
    d = ImageDraw.Draw(wipe)
    d.line([(half, 0), (half, before_img.height)], fill=(185, 138, 47), width=4)
    wipe.save(job / "slider_mid.png")

    scores = score(str(job / "before.jpg"), str(job / "after_matched.png"))
    qc = {**meta, "scores": scores, "auto_verdict": verdict(scores)}
    (job / "qc.json").write_text(json.dumps(qc, indent=2))

    # Stage 2: step-by-step plan + CAD budget generated from this redesign.
    room = _room_from(job.name)
    plan = build_plan(meta["mode"], room)
    plan["job"] = job.name
    plan["qc_gate"] = qc["auto_verdict"]
    (job / "plan.json").write_text(json.dumps(plan, indent=2))
    print(json.dumps({"qc": qc, "plan_total_cad": [plan["total_cad_low"], plan["total_cad_high"]]}, indent=2))


if __name__ == "__main__":
    if sys.argv[1] == "prepare":
        prepare(sys.argv[2], sys.argv[3], sys.argv[4])
    elif sys.argv[1] == "finish":
        finish(sys.argv[2], sys.argv[3])
    else:
        sys.exit(__doc__)
