"""몸이 곧 신원인 인물에게는 **옷 사진을 주지 않는다** (2026-09-19).

## 무엇이 났나 — 실측 (사용자 지적, 유료 두 판)

찰리(고릴라 비율 로봇)의 아웃룩 합성이 「몸이 두 번 그려진」 그림으로
나왔다. 사람 비율 몸통에 옷을 입히고 로봇 팔은 뒤에 따로 떠 있거나,
팔다리가 서너 개씩 겹쳤다.

참조 두 장이 **둘 다 몸**이었기 때문이다.

    image 1  찰리 (고릴라 비율 로봇 전신)
    image 2  **사람 모양 회색 마네킹이 입은 옷** — `character_outlook_ref`
             가 일부러 그렇게 만든다(옷을 보여 주려면 틀이 필요하다)

## 글로는 못 막았다

팩 v7 에 「마네킹은 진열대일 뿐, 옷만 가져와라」와 「이 몸에 맞게 다시
재단하라」를 넣고 **유료로 다시 만들었다.** 겹침은 줄었지만 몸은 여전히
사람이었다 — 카고바지에 사람 다리, 로봇 팔만 붙었다.

앞서 앞 샷 신원 혼입에서 **글 다섯 판이 전부 실패**했던 것과 같은 모양이다.
그래서 **두 번째 몸을 아예 안 보여준다.** 옷은 글로만 준다.
"""
from __future__ import annotations

import pathlib
import tempfile

import pytest


def _run(monkeypatch, *, derive: bool):
    """프로덕션 `generate_and_validate_reference` 를 그대로 태운다."""
    from app.modules.pipeline import ref_image_pipeline as rip

    seen: dict = {}

    class _Client:
        def set_context(self, **kw): pass
        def generate_image(self, prompt, labeled_references=None, **kw):
            seen["prompt"] = prompt
            seen["refs"] = [lab for lab, _ in (labeled_references or [])]
            return b"\x89PNG", 1.0

    monkeypatch.setattr(rip, "validate_reference_image",
                        lambda *a, **k: {"severity": "ok", "score": 90})
    monkeypatch.setattr("app.modules.png_metadata.embed_png_metadata",
                        lambda *a, **k: None)

    refs = [("Reference image 1 — the character's COMPLETE BODY", b"BODY")]
    if not derive:
        refs.append(("Outfit piece: 모포망토", b"OUTFIT"))

    with tempfile.TemporaryDirectory() as d:
        rip.generate_and_validate_reference(
            gemini_client=_Client(),
            entity_name="찰리 (모포망토)",
            entity_description="찰리 wearing 모포망토",
            entity_type="composite_derive" if derive else "composite",
            t2i_prompt="무시된다",
            output_dir=pathlib.Path(d),
            extra_references=refs,
            outlook_description="낡은 방수포를 어깨에 둘러 노끈으로 묶은 망토.",
        )
    return seen


def test_the_derive_prompt_carries_the_garment_as_text(monkeypatch):
    """★옷을 글로 줄 때 **그 글이 실제로 프롬프트에 들어가야** 한다.

    종전에는 `outlook_description` 자리에 `entity_description`(=「찰리
    wearing 모포망토」)을 넣고 있었다 — 옷을 글로 설명하는 문안에 **옷
    설명이 안 들어간 채로** 나갔다는 뜻이다.
    """
    seen = _run(monkeypatch, derive=True)
    assert "낡은 방수포" in seen["prompt"], (
        "옷 설명이 프롬프트에 안 실렸다 — 모델에게 그릴 재료가 없다")
    assert "DESCRIBED, not shown" in seen["prompt"]
    # 몸은 지켜야 한다
    assert "Do NOT give it" in seen["prompt"]
    assert "turnaround sheet" in seen["prompt"], "턴어라운드 방어가 또 사라졌다"


def test_the_human_composite_still_shows_the_outfit_photo(monkeypatch):
    """★사람 인물은 그대로 둔다 — 고칠 곳은 로봇 갈래뿐이다.

    사람끼리는 마네킹과 몸 모양이 같아 섞여도 탈이 없었고, 여기까지 바꾸면
    멀쩡한 합성 20장이 통째로 다시 돈다.
    """
    seen = _run(monkeypatch, derive=False)
    assert any("Outfit piece" in r for r in seen["refs"]), seen["refs"]
    assert "display mannequin" in seen["prompt"]


def test_phase3_drops_the_outfit_image_only_for_body_identity():
    """★조립부가 아니라 **프로덕션 소스**에서 그 갈래를 확인한다."""
    import inspect

    from app.services import reference_phase3_service as p3

    src = inspect.getsource(p3)
    assert "if not _derive:" in src, (
        "파생일 때 옷 사진을 빼는 갈래가 없다")
    assert "outlook_description=task.get" in src, (
        "옷 설명을 안 넘기면 파생 문안의 슬롯이 빈다")
