"""Tests for survey endpoints: vision health, analyze, save response, get history."""
import pytest
from unittest.mock import patch, MagicMock
from fastapi.testclient import TestClient


@pytest.fixture
def client():
    import sys
    sys.path.insert(0, "/Library/Development/CircuitForge/peregrine/.worktrees/feature-vue-spa")
    from dev_api import app
    return TestClient(app)


# ── GET /api/vision/health ───────────────────────────────────────────────────

def test_vision_health_available(client):
    """Returns available=true when vision service responds 200."""
    mock_resp = MagicMock()
    mock_resp.status_code = 200
    with patch("dev_api.requests.get", return_value=mock_resp):
        resp = client.get("/api/vision/health")
    assert resp.status_code == 200
    assert resp.json() == {"available": True}


def test_vision_health_unavailable(client):
    """Returns available=false when vision service times out or errors."""
    with patch("dev_api.requests.get", side_effect=Exception("timeout")):
        resp = client.get("/api/vision/health")
    assert resp.status_code == 200
    assert resp.json() == {"available": False}


# ── POST /api/jobs/{id}/survey/analyze ──────────────────────────────────────

def test_analyze_text_quick(client):
    """Text mode quick analysis returns output and source=text_paste."""
    mock_router = MagicMock()
    mock_router.complete.return_value = "1. B — best option"
    mock_router.config.get.return_value = ["claude_code", "vllm"]
    with patch("dev_api.LLMRouter", return_value=mock_router):
        resp = client.post("/api/jobs/1/survey/analyze", json={
            "text": "Q1: Do you prefer teamwork?\nA. Solo  B. Together",
            "mode": "quick",
        })
    assert resp.status_code == 200
    data = resp.json()
    assert data["source"] == "text_paste"
    assert "B" in data["output"]
    # System prompt must be passed for text path
    call_kwargs = mock_router.complete.call_args[1]
    assert "system" in call_kwargs
    assert "culture-fit survey" in call_kwargs["system"]


def test_analyze_text_detailed(client):
    """Text mode detailed analysis passes correct prompt."""
    mock_router = MagicMock()
    mock_router.complete.return_value = "Option A: good for... Option B: better because..."
    mock_router.config.get.return_value = []
    with patch("dev_api.LLMRouter", return_value=mock_router):
        resp = client.post("/api/jobs/1/survey/analyze", json={
            "text": "Q1: Describe your work style.",
            "mode": "detailed",
        })
    assert resp.status_code == 200
    assert resp.json()["source"] == "text_paste"


def test_analyze_image(client):
    """Image mode routes through vision path with NO system prompt."""
    mock_router = MagicMock()
    mock_router.complete.return_value = "1. C — collaborative choice"
    mock_router.config.get.return_value = ["vision_service", "claude_code"]
    with patch("dev_api.LLMRouter", return_value=mock_router):
        resp = client.post("/api/jobs/1/survey/analyze", json={
            "image_b64": "aGVsbG8=",
            "mode": "quick",
        })
    assert resp.status_code == 200
    data = resp.json()
    assert data["source"] == "screenshot"
    # No system prompt on vision path
    call_kwargs = mock_router.complete.call_args[1]
    assert "system" not in call_kwargs


def test_analyze_llm_failure(client):
    """Returns 500 when LLM raises an exception."""
    mock_router = MagicMock()
    mock_router.complete.side_effect = Exception("LLM unavailable")
    mock_router.config.get.return_value = []
    with patch("dev_api.LLMRouter", return_value=mock_router):
        resp = client.post("/api/jobs/1/survey/analyze", json={
            "text": "Q1: test",
            "mode": "quick",
        })
    assert resp.status_code == 500


# ── POST /api/jobs/{id}/survey/responses ────────────────────────────────────

def test_save_response_text(client):
    """Save text response writes to DB and returns id."""
    mock_db = MagicMock()
    with patch("dev_api._get_db", return_value=mock_db):
        with patch("dev_api.insert_survey_response", return_value=42) as mock_insert:
            resp = client.post("/api/jobs/1/survey/responses", json={
                "mode": "quick",
                "source": "text_paste",
                "raw_input": "Q1: test question",
                "llm_output": "1. B — good reason",
            })
    assert resp.status_code == 200
    assert resp.json()["id"] == 42
    # received_at generated by backend — not None
    call_args = mock_insert.call_args
    assert call_args[1]["received_at"] is not None or call_args[0][3] is not None


def test_save_response_with_image(client, tmp_path, monkeypatch):
    """Save image response writes PNG file and stores path in DB."""
    monkeypatch.setenv("STAGING_DB", str(tmp_path / "test.db"))
    with patch("dev_api.insert_survey_response", return_value=7) as mock_insert:
        with patch("dev_api.Path") as mock_path_cls:
            mock_path_cls.return_value.__truediv__ = lambda s, o: tmp_path / o
            resp = client.post("/api/jobs/1/survey/responses", json={
                "mode": "quick",
                "source": "screenshot",
                "image_b64": "aGVsbG8=",  # valid base64
                "llm_output": "1. B — reason",
            })
    assert resp.status_code == 200
    assert resp.json()["id"] == 7


# ── GET /api/jobs/{id}/survey/responses ─────────────────────────────────────

def test_get_history_empty(client):
    """Returns empty list when no history exists."""
    with patch("dev_api.get_survey_responses", return_value=[]):
        resp = client.get("/api/jobs/1/survey/responses")
    assert resp.status_code == 200
    assert resp.json() == []


def test_get_history_populated(client):
    """Returns history rows newest first."""
    rows = [
        {"id": 2, "survey_name": "Round 2", "mode": "detailed", "source": "text_paste",
         "raw_input": None, "image_path": None, "llm_output": "Option A is best",
         "reported_score": "90%", "received_at": "2026-03-21T14:00:00", "created_at": "2026-03-21T14:00:01"},
        {"id": 1, "survey_name": "Round 1", "mode": "quick", "source": "text_paste",
         "raw_input": "Q1: test", "image_path": None, "llm_output": "1. B",
         "reported_score": None, "received_at": "2026-03-21T12:00:00", "created_at": "2026-03-21T12:00:01"},
    ]
    with patch("dev_api.get_survey_responses", return_value=rows):
        resp = client.get("/api/jobs/1/survey/responses")
    assert resp.status_code == 200
    data = resp.json()
    assert len(data) == 2
    assert data[0]["id"] == 2
    assert data[0]["survey_name"] == "Round 2"
