"""CAMERA 블록 걷기가 **어디서 끝나는가** (2026-08-27).

`strip_camera_block` 은 종전에 `Compose the frame` 으로 시작하는 줄에서만
멈췄다. 그 문장은 팩 v6 에만 있고 **컴팩트 팩 v22 에는 없다** — grok 조립 +
confined 경로에서 CAMERA 이후 프롬프트 **전부**가 잘린 채 유료 호출로 갔다.
시네마틱 마감 절만이 아니라 그 뒤의 모든 절이.

고친 자리는 팩이 아니라 sanitizer 다. 컴팩트 스템에 종료 문구를 넣으면
**나가는 v22 바이트가 바뀌어** 완주본이 재생성된다. 다음 top-level 헤딩에서도
끝내되 **그 헤딩은 보존**하면 나가는 문안은 그대로고 잘리던 것만 안 잘린다.
"""

import pathlib

from app.modules.pipeline.confined_fp import (
    build_confined_gen_prompt,
    strip_camera_block,
    strip_confined_brief,
)
from app.modules.pipeline.still_recipe import attach_cinematic_finish

_PACKS = pathlib.Path(__file__).resolve().parents[3] / "prompts" / "_base"


def _camera_clause(version: str) -> str:
    return (_PACKS / "still_recipe" / version / "camera_frame_clause.md"
            ).read_text(encoding="utf-8").replace(
        "{body}", "eye level, medium shot")


def _brief(version: str) -> str:
    """실제 팩 문안으로 브리프 한 벌 — 마감 절은 실제 조립 함수가 붙인다.

    ★`cine_on=False` 다 (2026-08-27 변경). 이 시험이 지키는 것은
     「CAMERA 블록을 걷을 때 **그 뒤 절이 안 잘린다**」이고, 마감 절은
     그 뒤에 오는 절의 **표식**으로 쓸 뿐이다. 마감 소유권이 끝 단계
     한 곳으로 바뀌면서 `cine_on=True` 면 roll 에 마감이 안 붙는다 —
     표식이 사라지면 이 시험이 재던 것을 못 잰다.
    """
    body = (f"SHOT: a man stands.\n\n{_camera_clause(version)}\n\n"
            f"NO TEXT: none.")
    return attach_cinematic_finish(body, grok_backend=True, cine_on=False)


# ── 컴팩트 팩 — 이 판이 고친 자리 ────────────────────────────────────

def test_compact_pack_keeps_everything_after_the_camera_block():
    """v22 는 종료 문장이 없다 — 종전에는 뒤가 통째로 사라졌다."""
    out = strip_camera_block(_brief("22.202608180100"))

    assert "CAMERA & FRAME" not in out, "CAMERA 헤딩이 남았다"
    assert "Follow exactly" not in out, "CAMERA 본문이 남았다"
    assert "NO TEXT" in out, "CAMERA 뒤 절이 사라졌다"
    assert "CINEMATIC FINISH" in out, "마감 절이 사라졌다"


def test_compact_pack_survives_the_whole_confined_assembly():
    """★조각이 아니라 **실제 조립 함수**를 태운다.

    잘린 브리프가 그대로 유료 roll 로 간다 — 걷기 함수만 재고 조립을
    안 보면 그 사이에서 또 잘려도 못 본다.
    """
    prompt = build_confined_gen_prompt(
        "a narrow room, one man by the bench",
        _brief("22.202608180100"))

    assert "CAMERA & FRAME" not in prompt
    assert "NO TEXT" in prompt, "CAMERA 뒤 절이 사라졌다"
    assert "CINEMATIC FINISH" in prompt, "마감 절이 사라졌다"


# ── 옛 팩 — 바이트가 한 자도 안 바뀌어야 한다 ────────────────────────

def test_v6_pack_is_byte_identical_to_the_old_behaviour():
    """v6 에는 종료 문장이 있다 — 그 갈래는 종전 그대로여야 한다.

    옛 동작을 여기 다시 적어 대조한다(구현을 부르지 않는다 — 그러면
    같이 틀렸을 때 둘 다 초록이다).
    """
    def _old(prompt: str) -> str:
        out, in_cam = [], False
        for ln in prompt.split("\n"):
            s = ln.strip()
            if s.startswith("CAMERA & FRAME"):
                in_cam = True
                continue
            if in_cam:
                if s.startswith("Compose the frame"):
                    in_cam = False
                continue
            out.append(ln)
        return "\n".join(out)

    brief = _brief("6.202607192140")
    assert strip_camera_block(brief) == _old(brief)


def test_prompt_without_a_camera_block_is_untouched():
    plain = "SHOT: x.\n\nNO TEXT: none.\n\nCINEMATIC FINISH: y."
    assert strip_camera_block(plain) == plain
    assert strip_confined_brief(plain) == plain


# ── 걷기가 헤딩을 삼키지 않는다 ──────────────────────────────────────

def test_the_heading_that_ends_the_block_is_kept():
    """블록을 끝내는 헤딩은 **버리지 않는다** — 그 절은 CAMERA 것이 아니다."""
    probe = ("CAMERA & FRAME (x):\nsome camera text\n"
             "MORE CAMERA TEXT that is not a heading\n\n"
             "LIGHTING & MOOD: warm.\n\nNO TEXT: none.")
    out = strip_camera_block(probe)

    assert "some camera text" not in out
    assert "LIGHTING & MOOD: warm." in out, "블록을 끝낸 헤딩까지 버렸다"
    assert "NO TEXT: none." in out
