"""Task B6 — open-scope E2E: 실제 producer → wrapper → capture → flush → DB row.

scope 를 열고 실제 producer(floor_plan_render)를 mock client 로 호출하면 intermediate
image_asset 행이 정확한 role/stage/metadata 로 DB 에 생긴다. consumer write_bytes(producer
가 out_path 에 쓰는 것)는 capture 를 안 하므로 추가 행 0(producer 수렴점에서만 1행).
PG theroad_test, conftest 가 스키마 생성. 결정론(실 API 0).
"""

import base64
import json
import uuid
from datetime import datetime, timezone
from types import SimpleNamespace

from app.core.database import SessionLocal
from app.models.catalog import ProjectRegistry, UserAccount
from app.models.project import Episode, ImageAsset
from app.services.image_capture.context import generation_context

_BIG = b"\x89PNG\r\n\x1a\n" + b"\x00" * 4096


def _now() -> str:
    return datetime.now(timezone.utc).isoformat()


def _seed() -> tuple[str, str]:
    db = SessionLocal()
    try:
        uid = str(uuid.uuid4())
        db.add(UserAccount(
            id=uid, username=f"u_{uid[:8]}", display_name="t", password_hash="x",
            role="admin", created_at=_now(), updated_at=_now(),
        ))
        db.commit()
        pid = str(uuid.uuid4())
        db.add(ProjectRegistry(
            id=pid, name="OpenScope E2E", created_by=uid,
            created_at=_now(), updated_at=_now(),
        ))
        eid = str(uuid.uuid4())
        db.add(Episode(
            id=eid, project_id=pid, episode_number=1, title="P",
            source_filename="p.pdf", source_path="p.pdf",
            created_at=_now(), updated_at=_now(),
        ))
        db.commit()
        return pid, eid
    finally:
        db.close()


class _Images:
    def __init__(self):
        self._b64 = base64.b64encode(_BIG).decode("ascii")

    def generate(self, **kw):
        return SimpleNamespace(data=[SimpleNamespace(b64_json=self._b64)])

    def edit(self, **kw):
        return SimpleNamespace(data=[SimpleNamespace(b64_json=self._b64)])


class _Client:
    def __init__(self):
        self.images = _Images()


def test_open_scope_producer_creates_one_intermediate_row(tmp_path):
    pid, eid = _seed()
    from app.modules.pipeline.floor_plan_render import render_one_floor_plan

    out = tmp_path / "fp.png"
    with generation_context(pid, eid, "floor_plan_image") as q:
        res = render_one_floor_plan(
            openai_client=_Client(), image_model="gpt-image-2.5-sunburst",
            prompt="draw a plan", out_path=out, ref_paths=[], fp_id="fp1",
        )
        assert res.status == "ok"
        assert out.read_bytes() == _BIG  # producer 의 consumer write_bytes(파일)
        assert len(q._items) == 1  # capture 1건 enqueue

    # scope 종료 → flush → DB row 1개(producer 수렴점에서만, consumer write 는 0행)
    db = SessionLocal()
    try:
        rows = db.query(ImageAsset).filter(
            ImageAsset.project_id == pid,
            ImageAsset.is_intermediate == True,  # noqa: E712
        ).all()
        assert len(rows) == 1
        r = rows[0]
        assert r.asset_type == "generated"
        assert r.is_intermediate is True
        assert r.pipeline_role == "floor_plan"
        assert r.stage == "floor_plan_image"
        assert r.status == "generated"
        assert r.episode_id == eid
        assert json.loads(r.pipeline_metadata_json)["budget_source"] == "floor_plan_render.generate"
        # reference_image_ids 오염 금지
        assert "floor_plan" not in (r.reference_image_ids or "")
    finally:
        db.close()
