"""src.migrator のプロンプト生成・retry ロジック（API非依存部分）の単体テスト。

anthropic SDK は conftest でスタブ済み（未導入環境でも実行可能）。
"""
import pathlib
import sys

import pytest

ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))

from src.migrator import build_user_prompt, build_ecosystem_prompt, Migrator

import anthropic as _anthropic

# 本物の anthropic SDK では例外クラスの生成シグネチャがバージョン依存のため、
# retry テストは conftest のスタブ環境でのみ実行する（純粋ロジックの検証目的）。
_USING_STUB = not hasattr(_anthropic, "__file__")


class TestBuildUserPrompt:
    def test_includes_source_and_target_syntax_names(self):
        p = build_user_prompt("print('x')", "Python", "Rust")
        assert "Python" in p and "Rust" in p
        assert "print('x')" in p
        assert "--- SOURCE (Python) ---" in p

    def test_extra_instructions_included(self):
        p = build_user_prompt("x", "Python", "Go", extra_instructions="keep comments")
        assert "keep comments" in p

    def test_context_snippets_injected(self):
        p = build_user_prompt(
            "x", "Python", "Go",
            context_snippets=[("types.go", "type T struct{}")],
        )
        assert "ALREADY-CONVERTED PROJECT CONTEXT" in p
        assert "types.go" in p and "type T struct{}" in p

    def test_no_context_section_when_absent(self):
        p = build_user_prompt("x", "Python", "Go")
        assert "PROJECT CONTEXT" not in p


class TestBuildEcosystemPrompt:
    def test_mentions_both_filenames(self):
        p = build_ecosystem_prompt("flask\n", "requirements.txt", "go.mod", "Python", "Go")
        assert "requirements.txt" in p and "go.mod" in p
        assert "flask" in p


@pytest.mark.skipif(not _USING_STUB, reason="実 anthropic SDK では例外生成がバージョン依存のためスタブ環境のみ")
class TestRetryBackoff:
    def test_call_api_retries_then_raises_on_persistent_rate_limit(self, monkeypatch):
        import anthropic

        calls = {"n": 0}

        class _FakeMessages:
            def create(self, **kwargs):
                calls["n"] += 1
                raise anthropic.RateLimitError("429")

        m = Migrator(api_key="dummy", model="claude-sonnet-4-20250514")
        m.client.messages = _FakeMessages()
        # sleep を無効化して高速に
        monkeypatch.setattr("src.migrator.time.sleep", lambda *_: None)

        retries = []
        m._on_retry = lambda attempt, wait, err: retries.append(attempt)

        with pytest.raises(Exception):
            m._call_api("system", "user")
        # 複数回リトライしてから諦める
        assert calls["n"] >= 2
        assert retries  # リトライ通知が呼ばれた
