#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""三视图自动预处理：从三视图原图裁出正面视图，作为第一参考图（身份锚定）；
完整三视图保留为第二参考图（外观补充）。

用法: python3 turnaround_prep.py <三视图原图> [--out-dir 输出目录] [--keep-full]
输出:
  pic1_front.jpg  —— 裁出的正面视图（<Picture 1>）
  pic2_full.jpg   —— 完整三视图原图（<Picture 2>）
"""
import argparse
import json
import subprocess
import sys
from pathlib import Path

VISION_SH = str(Path.home() / ".dsh/skills/vision-identify/scripts/vision-identify.sh")


def locate_front_view(image_path: str) -> dict:
    """用 DeepSeek-V4-Flash-Vision-Exp 定位三视图中正面视图的位置。

    返回 {"is_turnaround": bool, "front_region": "left"/"middle"/"right"/"unknown",
          "layout": "horizontal"/"vertical"/"unknown", "note": str}
    """
    question = (
        "这是一张参考图。请判断：1) 它是否是角色三视图/多角度设定图（character turnaround sheet）？"
        "2) 如果是，三个视图是横向排列还是纵向排列？"
        "3) 正面视图（front view，人物正对镜头）在最左侧、中间还是最右侧？"
        "4) 如果只有一个视图（不是多视图），说明'不是多视图'。"
        "只输出 JSON：{\"is_turnaround\": true/false, \"layout\": \"horizontal\"/\"vertical\"/\"single\"/\"unknown\", "
        "\"front_region\": \"left\"/\"middle\"/\"right\"/\"unknown\", \"note\": \"简短说明\"}"
    )
    r = subprocess.run([VISION_SH, image_path, "--question", question],
                       capture_output=True, text=True, timeout=120)
    out = (r.stdout or "").strip()
    # 提取 JSON
    try:
        start = out.find("{")
        end = out.rfind("}") + 1
        data = json.loads(out[start:end])
    except Exception:
        data = {"is_turnaround": True, "layout": "horizontal", "front_region": "unknown", "note": "JSON解析失败: " + out[:200]}
    return data


def crop_front(image_path: str, region: str, layout: str, out_path: str) -> bool:
    """按定位结果裁剪正面视图。成功返回 True，失败返回 False（调用方回退到整图）。"""
    try:
        from PIL import Image
    except ImportError:
        return False
    img = Image.open(image_path)
    w, h = img.size
    if layout == "vertical" and h > w:
        # 纵向三视图：三个视图上下排列，正面通常在最上（或最下）
        parts = 3
        slot = 0 if region in ("top", "left", "unknown") else (2 if region == "bottom" else 1)
        if region == "middle":
            slot = 1
        box = (0, int(h * slot / parts), w, int(h * (slot + 1) / parts))
    else:
        # 横向三视图（最常见）：三个视图左右排列，正面通常在中间或左侧
        parts = 3
        slot = 0 if region == "left" else (1 if region in ("middle", "unknown") else 2)
        box = (int(w * slot / parts), 0, int(w * (slot + 1) / parts), h)
    crop = img.crop(box)
    # 稍微向外扩一点，避免裁太紧
    crop = crop.resize((max(crop.width, 400), max(crop.height, 400)))
    crop.convert("RGB").save(out_path, quality=92)
    return True


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("image", help="三视图原图路径")
    ap.add_argument("--out-dir", default=".", help="输出目录")
    args = ap.parse_args()

    out_dir = Path(args.out_dir)
    out_dir.mkdir(parents=True, exist_ok=True)
    src = Path(args.image)
    if not src.exists():
        print(f"错误: 图片不存在 {src}")
        sys.exit(1)

    # 1. 识图定位正面
    info = locate_front_view(str(src))
    print(f"识图定位: {json.dumps(info, ensure_ascii=False)}")

    # 2. 完整原图作为第二参考
    full_path = out_dir / "pic2_full.jpg"
    try:
        from PIL import Image
        Image.open(src).convert("RGB").save(full_path, quality=92)
    except Exception:
        import shutil
        shutil.copy(src, full_path)

    # 3. 裁正面作为第一参考
    front_path = out_dir / "pic1_front.jpg"
    ok = False
    if info.get("is_turnaround") and info.get("layout") != "single":
        ok = crop_front(str(src), info.get("front_region", "unknown"),
                        info.get("layout", "horizontal"), str(front_path))
    if not ok:
        # 回退：无法定位/不是多视图 → 用整图当第一参考
        try:
            from PIL import Image
            Image.open(src).convert("RGB").save(front_path, quality=92)
        except Exception:
            import shutil
            shutil.copy(src, front_path)
        print("⚠️ 未能可靠裁出正面视图，pic1 使用整图（可能仍是三视图）")

    print(f"✅ pic1_front.jpg: {front_path}")
    print(f"✅ pic2_full.jpg:  {full_path}")
    print(json.dumps({"pic1": str(front_path), "pic2": str(full_path), "info": info}, ensure_ascii=False))


if __name__ == "__main__":
    main()
