"""ReferencePhase1Service 단위 테스트 — F24.4.2.

검증 대상:
1. `run()` 시그니처 — ctx 단일 인자
2. `ReferencePipelineContext` dataclass 기본값
3. orchestrator `__init__`이 `_phase1_svc`로 Phase1Service를 주입
"""
from __future__ import annotations

import inspect
from pathlib import Path
from unittest.mock import MagicMock

from app.services.reference_phase1_service import ReferencePhase1Service
from app.services.reference_pipeline_context import ReferencePipelineContext
from app.services.reference_pipeline_orchestrator import ReferencePipelineOrchestrator


# ──────────────────────────────────────────────────────────────────────
# 1) run 시그니처 — ctx 단일 인자 + Optional[Dict] 반환
# ──────────────────────────────────────────────────────────────────────


def test_phase1_run_signature():
    sig = inspect.signature(ReferencePhase1Service.run)
    params = list(sig.parameters.keys())
    assert params == ["self", "ctx"]


# ──────────────────────────────────────────────────────────────────────
# 2) ReferencePipelineContext 기본값
# ──────────────────────────────────────────────────────────────────────


def test_context_defaults():
    ctx = ReferencePipelineContext(
        episode_id="e1",
        episode=MagicMock(),
        mode="resume",
        skip_composite=False,
        ip=None,
        entities=[],
        entity_by_id={},
        deps={},
        batches=[],
        reference_dir=Path("/tmp"),
        gemini_client=MagicMock(),
        max_concurrent=3,
        progress=MagicMock(),
        ref_cp=MagicMock(),
    )
    assert ctx.ref_image_map == {}
    assert ctx.already_done == set()
    assert ctx.low_freq_skip_ids == set()
    assert ctx.o00_char_ids == set()
    assert ctx.generated_count == 0
    assert ctx.failed_count == 0
    assert ctx.outlook_generated == 0
    assert ctx.outlook_skipped == 0
    assert ctx.composite_generated == 0
    assert ctx.composite_skipped == 0
    assert ctx.total_to_gen == 0  # entities 비어있음, skipped_count=0


def test_context_total_to_gen_property():
    ctx = ReferencePipelineContext(
        episode_id="e1",
        episode=MagicMock(),
        mode="resume",
        skip_composite=False,
        ip=None,
        entities=[{"id": f"e{i}"} for i in range(10)],
        entity_by_id={},
        deps={},
        batches=[],
        reference_dir=Path("/tmp"),
        gemini_client=MagicMock(),
        max_concurrent=3,
        progress=MagicMock(),
        ref_cp=MagicMock(),
        skipped_count=3,
    )
    assert ctx.total_to_gen == 7


# ──────────────────────────────────────────────────────────────────────
# 3) orchestrator wiring — __init__이 ReferencePhase1Service를 주입
# ──────────────────────────────────────────────────────────────────────


def test_orchestrator_wires_phase1_service(monkeypatch):
    captured = {}

    class _Spy(ReferencePhase1Service):
        def __init__(self, *args, **kwargs):
            captured["kwargs"] = kwargs
            super().__init__(*args, **kwargs)

    monkeypatch.setattr(
        "app.services.reference_pipeline_orchestrator.ReferencePhase1Service",
        _Spy,
    )

    logger = MagicMock()
    orch = ReferencePipelineOrchestrator(
        db=MagicMock(), project_id="p1", actor_id="u1", activity_logger=logger,
    )
    assert isinstance(orch._phase1_svc, _Spy)
    assert isinstance(orch._phase1_svc, ReferencePhase1Service)
    assert captured["kwargs"]["project_id"] == "p1"
    assert captured["kwargs"]["actor_id"] == "u1"
    assert captured["kwargs"]["activity_logger"] is logger
