import json
import pytest
import respx
import httpx

from app.interpret import pipeline
from app.interpret.pipeline import SajuError


@pytest.fixture(autouse=True)
def _patch_key(monkeypatch):
    monkeypatch.setattr(pipeline, "ANTHROPIC_API_KEY", "test-key")


SAJU_ITEM_KEYS = [
    "기질", "오행밸런스", "지지상호작용", "신살영향",
    "재물운", "직업적성", "애정운", "건강운",
    "현재대운", "올해세운", "인생황금기", "종합조언",
]


def _valid_saju_response():
    items = []
    for k in SAJU_ITEM_KEYS:
        items.append({
            "key": k, "title": "...", "content": "...",
            "evidence": {"saju_element": "...", "reasoning": "..."}
        })
    return {
        "items": items,
        "summary": "...",
        "advice": "...",
        "warning": None,
        "confidence": "medium",
    }


def _valid_compat_response():
    return {
        "summary": "...",
        "strengths": [
            {"title": "오행 상생", "explanation": "...", "evidence": "..."},
            {"title": "...", "explanation": "...", "evidence": "..."},
        ],
        "challenges": [
            {"title": "...", "explanation": "...", "evidence": "..."},
            {"title": "...", "explanation": "...", "evidence": "..."},
        ],
        "advice": "...",
        "warning": None,
        "confidence": "high",
    }


def _claude_envelope(text: str, in_tok=200, out_tok=400):
    return {
        "content": [{"type": "text", "text": text}],
        "usage": {"input_tokens": in_tok, "output_tokens": out_tok},
    }


@respx.mock
async def test_saju_interpret_success():
    respx.post("https://api.anthropic.com/v1/messages").mock(
        return_value=httpx.Response(200, json=_claude_envelope(json.dumps(_valid_saju_response())))
    )
    result = await pipeline.interpret_saju(
        saju={"day_stem": "辛"},
        analysis={"element_balance": {"金": 3.0}},
        daeun=[{"age": 10}],
        current_year=2026,
    )
    assert result["reroll_count"] == 0
    assert result["tokens_in"] == 200
    assert result["cost_usd"] > 0


@respx.mock
async def test_saju_codeblock_stripped():
    text = "```json\n" + json.dumps(_valid_saju_response()) + "\n```"
    respx.post("https://api.anthropic.com/v1/messages").mock(
        return_value=httpx.Response(200, json=_claude_envelope(text))
    )
    result = await pipeline.interpret_saju(saju={}, analysis={}, daeun=[], current_year=2026)
    assert "interpretation_json" in result


@respx.mock
async def test_saju_reroll_then_success():
    valid = json.dumps(_valid_saju_response())
    invalid = json.dumps({"items": [], "summary": "...", "advice": "", "confidence": "medium"})
    respx.post("https://api.anthropic.com/v1/messages").mock(
        side_effect=[
            httpx.Response(200, json=_claude_envelope(invalid)),
            httpx.Response(200, json=_claude_envelope(valid)),
        ]
    )
    result = await pipeline.interpret_saju(saju={}, analysis={}, daeun=[], current_year=2026)
    assert result["reroll_count"] == 1


@respx.mock
async def test_saju_reroll_fail_raises():
    invalid = json.dumps({"items": [], "summary": "...", "advice": "", "confidence": "medium"})
    respx.post("https://api.anthropic.com/v1/messages").mock(
        return_value=httpx.Response(200, json=_claude_envelope(invalid))
    )
    with pytest.raises(SajuError):
        await pipeline.interpret_saju(saju={}, analysis={}, daeun=[], current_year=2026)


@respx.mock
async def test_saju_http_error():
    respx.post("https://api.anthropic.com/v1/messages").mock(
        return_value=httpx.Response(500, text="boom")
    )
    with pytest.raises(SajuError):
        await pipeline.interpret_saju(saju={}, analysis={}, daeun=[], current_year=2026)


@respx.mock
async def test_compat_interpret_success():
    respx.post("https://api.anthropic.com/v1/messages").mock(
        return_value=httpx.Response(200, json=_claude_envelope(json.dumps(_valid_compat_response())))
    )
    result = await pipeline.interpret_compat(
        saju_a={"day_stem": "辛"}, saju_b={"day_stem": "丁"},
        analysis_a={}, analysis_b={},
        score=85, breakdown={"day_master_element": {"score": 25}},
    )
    assert result["reroll_count"] == 0
    assert "interpretation_json" in result


@respx.mock
async def test_compat_reroll_then_success():
    valid = json.dumps(_valid_compat_response())
    invalid = json.dumps({"summary": "...", "strengths": [], "challenges": [], "advice": "", "confidence": "high"})
    respx.post("https://api.anthropic.com/v1/messages").mock(
        side_effect=[
            httpx.Response(200, json=_claude_envelope(invalid)),
            httpx.Response(200, json=_claude_envelope(valid)),
        ]
    )
    result = await pipeline.interpret_compat(
        saju_a={}, saju_b={}, analysis_a={}, analysis_b={},
        score=50, breakdown={},
    )
    assert result["reroll_count"] == 1


def test_calc_cost():
    cost = pipeline.calc_cost(1_000_000, 1_000_000)
    assert cost == pipeline.SAJU_COST_INPUT_PER_M + pipeline.SAJU_COST_OUTPUT_PER_M
