"""참조가 **그림 프롬프트 글자**까지 가나. ★유료 0.

Codex 가 활성화 전에 보라고 한 것 ②③ (2026-08-31) —

    ②이미지 프롬프트에 각 `Image N` 과 **역할**이 다 실리나
    ③기존 `background_general` 역할을 재사용할 수 있나

끝점은 `prompt_service.resolve_ref_roles` 다 — `labeled_refs` 를 프롬프트
문구(`Reference image N: …`)와 지시문으로 바꾸는 자리.
"""
from __future__ import annotations

import pytest

from app.services.prompt_service import (REF_ROLE_VALUES, RefRoleError,
                                         make_labeled_ref_payload,
                                         resolve_ref_roles)


def _payload(roles, labels=None):
    n = len(roles)
    labels = labels or [f"라벨{i}" for i in range(n)]
    return make_labeled_ref_payload(
        labeled_refs=[(labels[i], b"x") for i in range(n)],
        ref_roles=list(roles),
        ref_role_metadata=[{} for _ in range(n)],
        attached_meta=[("background", f"B{i}") for i in range(n)])


class TestEveryRefReachesThePrompt:
    """★② 각 `Image N` 과 역할이 **다** 실리나."""

    def test_three_backgrounds_all_appear(self):
        got = resolve_ref_roles(_payload(
            ["background_chain_ref", "background_general", "prop_ref"]))
        assert len(got.ref_roles) == 3, f"★빠진 것이 있다: {got.ref_roles}"
        for i in (1, 2, 3):
            assert any(f"image {i}" in t.lower() for t in got.ref_roles), \
                f"★Image {i} 가 프롬프트에 없다"

    def test_each_one_gets_an_instruction(self):
        got = resolve_ref_roles(_payload(
            ["background_chain_ref", "background_general", "prop_ref"]))
        assert len(got.ref_instructions) >= 3, \
            f"★지시문이 모자란다: {got.ref_instructions}"

    def test_the_order_is_kept(self):
        got = resolve_ref_roles(_payload(
            ["background_general", "prop_ref"], labels=["첫째", "둘째"]))
        idx = [t.lower().index("image ") for t in got.ref_roles[:2]]
        assert idx, "★차례를 못 읽는다"


class TestCanBackgroundGeneralBeReused:
    """★③ — **절반만** 된다 (실측).

    `background_general` 이 내는 지시문은 —

        「image N 의 **빛·건축·분위기**를 쓰라」

    그것은 **그 장소의 공기**를 가져오라는 말이다. `location_part` 의
    **맥락** 멤버(그 장소)에는 맞지만 **상세** 멤버(회전 간판 자체)에는
    **틀리다** — 간판 근접 사진에서 「분위기」를 가져오라고 하면 안 된다.

    ★그래서 맥락은 `background_general` 을 **재사용**하고, 상세는 **새 역할**이
     필요하다. Codex 가 「새 role 을 더하는 것은 되지만 새 slot 은 아니다」라고
     한 그 자리다.
    """

    def test_it_talks_about_atmosphere_not_the_object(self):
        got = resolve_ref_roles(_payload(["background_general"]))
        line = " ".join(got.ref_instructions).lower()
        assert "mood" in line or "lighting" in line, \
            f"★분위기 지시가 아니다: {got.ref_instructions}"

    def test_the_object_role_says_include_the_object(self):
        """★견줌 — 물건 역할은 「그 물건을 넣어라」고 한다."""
        got = resolve_ref_roles(_payload(["prop_ref"]))
        line = " ".join(got.ref_instructions).lower()
        assert "include the object" in line, f"★{got.ref_instructions}"

    def test_the_two_instructions_differ(self):
        """★그래서 상세를 `background_general` 로 보내면 **틀린 말**이 간다."""
        a = resolve_ref_roles(_payload(["background_general"])).ref_instructions
        b = resolve_ref_roles(_payload(["prop_ref"])).ref_instructions
        assert a[0] != b[0]


class TestANewRoleMustBeDeclared:
    """★모르는 역할은 **조용히 안 흘러간다** — 즉시 선다.

    그래서 상세 역할을 더할 때 `REF_ROLE_VALUES` 에 **선언**하고 갈래를
    쓰는 것 말고는 길이 없다. 이것이 「slot 이 아니라 role 을 더한다」의 뜻이다.
    """

    def test_an_undeclared_role_stops(self):
        with pytest.raises(RefRoleError):
            _payload(["grounding_detail_ref"])

    def test_the_enum_is_the_gate(self):
        assert "background_general" in REF_ROLE_VALUES
        assert "grounding_detail_ref" not in REF_ROLE_VALUES

    def test_the_lists_must_stay_parallel(self):
        with pytest.raises(RefRoleError):
            make_labeled_ref_payload(
                labeled_refs=[("a", b"x"), ("b", b"y")],
                ref_roles=["background_general"],
                ref_role_metadata=[{}, {}],
                attached_meta=[("background", "B0"), ("background", "B1")])
