import pytest
from unittest.mock import patch, AsyncMock
from fastapi.testclient import TestClient

from app.main import app
from app import db as db_module


@pytest.fixture(autouse=True)
def fresh_db(monkeypatch, tmp_path):
    db_file = tmp_path / "test_saju.db"
    monkeypatch.setattr(db_module, "DB_PATH", str(db_file))
    db_module.init_db()
    yield
    try:
        if db_file.exists():
            db_file.unlink()
    except PermissionError:
        pass


def _interpret_result(interp_json=None):
    if interp_json is None:
        interp_json = {"items": [], "summary": "...", "advice": "...", "warning": None, "confidence": "medium"}
    return {
        "interpretation_json": interp_json,
        "model": "claude-sonnet-4-6",
        "tokens_in": 200, "tokens_out": 400, "cost_usd": 0.01,
        "latency_ms": 1200, "reroll_count": 0,
    }


def test_health():
    with TestClient(app) as c:
        r = c.get("/health")
        assert r.status_code == 200
        assert r.json() == {"ok": True}


def test_saju_interpret_endpoint(monkeypatch):
    """saju interpret이 pipeline mock으로 동작 + 신규 필드 검증."""
    async def fake_interpret(*args, **kwargs):
        return _interpret_result()

    from app.routers import saju as saju_router
    monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)

    with TestClient(app) as c:
        r = c.post("/api/saju/interpret", json={
            "year": 1990, "month": 5, "day": 15, "hour": 14,
            "gender": "male", "calendar_type": "solar"
        })
        assert r.status_code == 200, r.text
        data = r.json()
        assert "saju" in data
        assert "analysis" in data
        assert "daeun" in data
        assert "reading_id" in data
        assert data["reading_id"] > 0
        # 신규 필드
        assert "fortune_scores" in data
        for k in ("wealth", "romance", "social", "career", "overall"):
            assert k in data["fortune_scores"]
            assert 0 <= data["fortune_scores"][k] <= 100
        assert "lucky" in data
        for k in ("color", "number", "direction", "good_signs", "warnings"):
            assert k in data["lucky"]
        assert "monthly_flow" in data
        assert len(data["monthly_flow"]) == 12


def test_saju_list_get_cycle(monkeypatch):
    async def fake_interpret(*args, **kwargs):
        return _interpret_result()
    from app.routers import saju as saju_router
    monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)

    with TestClient(app) as c:
        # save
        rid = c.post("/api/saju/interpret", json={
            "year": 1990, "month": 5, "day": 15, "hour": 14,
            "gender": "male", "calendar_type": "solar"
        }).json()["reading_id"]
        # list
        assert c.get("/api/saju/readings").json()["total"] == 1
        # get
        r = c.get(f"/api/saju/readings/{rid}")
        assert r.status_code == 200
        assert r.json()["birth_year"] == 1990


def test_saju_patch_and_delete(monkeypatch):
    async def fake_interpret(*args, **kwargs):
        return _interpret_result()
    from app.routers import saju as saju_router
    monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)

    with TestClient(app) as c:
        rid = c.post("/api/saju/interpret", json={
            "year": 1990, "month": 5, "day": 15, "hour": 14,
            "gender": "male", "calendar_type": "solar"
        }).json()["reading_id"]

        r = c.patch(f"/api/saju/readings/{rid}", json={"favorite": True, "memo": "메모"})
        assert r.status_code == 200
        row = c.get(f"/api/saju/readings/{rid}").json()
        assert row["favorite"] == 1
        assert row["memo"] == "메모"

        r = c.delete(f"/api/saju/readings/{rid}")
        assert r.status_code == 200
        assert c.get(f"/api/saju/readings/{rid}").status_code == 404


def test_saju_get_404():
    with TestClient(app) as c:
        assert c.get("/api/saju/readings/9999").status_code == 404


def test_saju_current_fortune(monkeypatch):
    async def fake_interpret(*args, **kwargs):
        return _interpret_result()
    from app.routers import saju as saju_router
    monkeypatch.setattr(saju_router.pipeline, "interpret_saju", fake_interpret)

    with TestClient(app) as c:
        rid = c.post("/api/saju/interpret", json={
            "year": 1990, "month": 5, "day": 15, "hour": 14,
            "gender": "male", "calendar_type": "solar"
        }).json()["reading_id"]
        r = c.get(f"/api/saju/current-fortune?reading_id={rid}")
        assert r.status_code == 200
        data = r.json()
        assert "seun" in data
        assert data["seun"]["stem"]


def test_compat_interpret(monkeypatch):
    async def fake_compat(*args, **kwargs):
        return {
            "interpretation_json": {"summary": "...", "strengths": [
                {"title": "A", "explanation": "B", "evidence": "C"},
                {"title": "A2", "explanation": "B2", "evidence": "C2"},
            ], "challenges": [
                {"title": "D", "explanation": "E", "evidence": "F"},
                {"title": "D2", "explanation": "E2", "evidence": "F2"},
            ], "advice": "...", "warning": None, "confidence": "high"},
            "model": "claude-sonnet-4-6",
            "tokens_in": 300, "tokens_out": 500, "cost_usd": 0.015,
            "latency_ms": 1500, "reroll_count": 0,
        }
    from app.routers import compat as compat_router
    monkeypatch.setattr(compat_router.pipeline, "interpret_compat", fake_compat)

    with TestClient(app) as c:
        r = c.post("/api/saju/compat/interpret", json={
            "person_a": {"year": 1990, "month": 5, "day": 15, "hour": 14, "gender": "male", "calendar_type": "solar"},
            "person_b": {"year": 1992, "month": 8, "day": 8, "hour": 18, "gender": "female", "calendar_type": "solar"},
        })
        assert r.status_code == 200, r.text
        data = r.json()
        assert "score" in data
        assert "saju_a" in data
        assert "saju_b" in data


def test_compat_list_get_cycle(monkeypatch):
    async def fake_compat(*args, **kwargs):
        return {
            "interpretation_json": {"summary": "...", "strengths": [
                {"title": "a", "explanation": "b", "evidence": "c"},
                {"title": "a", "explanation": "b", "evidence": "c"},
            ], "challenges": [
                {"title": "d", "explanation": "e", "evidence": "f"},
                {"title": "d", "explanation": "e", "evidence": "f"},
            ], "advice": "", "warning": None, "confidence": "medium"},
            "model": "x", "tokens_in": 0, "tokens_out": 0, "cost_usd": 0.0,
            "latency_ms": 0, "reroll_count": 0,
        }
    from app.routers import compat as compat_router
    monkeypatch.setattr(compat_router.pipeline, "interpret_compat", fake_compat)

    with TestClient(app) as c:
        rid = c.post("/api/saju/compat/interpret", json={
            "person_a": {"year": 1990, "month": 5, "day": 15, "hour": 14, "gender": "male", "calendar_type": "solar"},
            "person_b": {"year": 1992, "month": 8, "day": 8, "hour": 18, "gender": "female", "calendar_type": "solar"},
        }).json()["reading_id"]

        assert c.get("/api/saju/compat/readings").json()["total"] == 1
        r = c.get(f"/api/saju/compat/readings/{rid}")
        assert r.status_code == 200
        assert r.json()["score"] >= 0


def test_compat_patch_and_delete(monkeypatch):
    async def fake_compat(*args, **kwargs):
        return {
            "interpretation_json": {"summary": "...", "strengths": [
                {"title": "a", "explanation": "b", "evidence": "c"},
                {"title": "a", "explanation": "b", "evidence": "c"},
            ], "challenges": [
                {"title": "d", "explanation": "e", "evidence": "f"},
                {"title": "d", "explanation": "e", "evidence": "f"},
            ], "advice": "", "warning": None, "confidence": "medium"},
            "model": "x", "tokens_in": 0, "tokens_out": 0, "cost_usd": 0.0,
            "latency_ms": 0, "reroll_count": 0,
        }
    from app.routers import compat as compat_router
    monkeypatch.setattr(compat_router.pipeline, "interpret_compat", fake_compat)

    with TestClient(app) as c:
        rid = c.post("/api/saju/compat/interpret", json={
            "person_a": {"year": 1990, "month": 5, "day": 15, "hour": 14, "gender": "male", "calendar_type": "solar"},
            "person_b": {"year": 1992, "month": 8, "day": 8, "hour": 18, "gender": "female", "calendar_type": "solar"},
        }).json()["reading_id"]

        r = c.patch(f"/api/saju/compat/readings/{rid}", json={"favorite": True, "memo": "좋은 궁합"})
        assert r.status_code == 200
        row = c.get(f"/api/saju/compat/readings/{rid}").json()
        assert row["favorite"] == 1

        r = c.delete(f"/api/saju/compat/readings/{rid}")
        assert r.status_code == 200
        assert c.get(f"/api/saju/compat/readings/{rid}").status_code == 404


def test_compat_get_404():
    with TestClient(app) as c:
        assert c.get("/api/saju/compat/readings/9999").status_code == 404
