"""Performance regression tests: survey list annotations + streaming results."""

import pytest
from django.contrib.auth import get_user_model
from django.db import connection
from django.test.utils import CaptureQueriesContext
from rest_framework.test import APIClient

from apps.hr.models import Survey, SurveyResponse

User = get_user_model()

QUESTIONS = [
    {"id": "q1", "label": "Pick one", "type": "single_choice"},
    {"id": "q2", "label": "Say more", "type": "text"},
]


@pytest.fixture
def admin(db):
    return User.objects.create_superuser(email="admin@test.local", password="x")


@pytest.fixture
def client(admin):
    c = APIClient()
    c.force_authenticate(admin)
    return c


@pytest.fixture
def survey(admin):
    return Survey.objects.create(title="S", description="d", questions=QUESTIONS,
                                 status="open", created_by=admin)


def _rows(resp):
    body = resp.json()
    return body["results"] if isinstance(body, dict) and "results" in body else body


def _respond(survey, user, q1="yes", q2=""):
    return SurveyResponse.objects.create(
        survey=survey, respondent=user,
        answers=[{"question_id": "q1", "value": q1},
                 {"question_id": "q2", "value": q2}],
    )


@pytest.mark.django_db
class TestSurveyListAnnotations:
    def test_response_count_and_has_responded(self, client, admin, survey):
        other = User.objects.create_user(email="o@test.local", password="x")
        _respond(survey, admin)
        _respond(survey, other)

        row = _rows(client.get("/api/surveys/"))[0]
        assert row["response_count"] == 2
        assert row["has_responded"] is True

    def test_has_responded_false_for_non_respondent(self, client, admin, survey):
        other = User.objects.create_user(email="o@test.local", password="x")
        _respond(survey, other)
        row = _rows(client.get("/api/surveys/"))[0]
        assert row["response_count"] == 1
        assert row["has_responded"] is False

    def test_queries_constant_in_rows(self, client, admin):
        s0 = Survey.objects.create(title="S0", description="d", questions=QUESTIONS,
                                   status="open", created_by=admin)
        _respond(s0, admin)
        with CaptureQueriesContext(connection) as small:
            client.get("/api/surveys/")
        users = [User.objects.create_user(email=f"u{i}@test.local", password="x")
                 for i in range(3)]
        for i in range(1, 6):
            s = Survey.objects.create(title=f"S{i}", description="d", questions=QUESTIONS,
                                      status="open", created_by=admin)
            for u in users:
                _respond(s, u)
        with CaptureQueriesContext(connection) as big:
            client.get("/api/surveys/")
        assert len(big.captured_queries) == len(small.captured_queries)


@pytest.mark.django_db
class TestSurveyResults:
    def test_distribution_and_values(self, client, admin, survey):
        users = [User.objects.create_user(email=f"u{i}@test.local", password="x")
                 for i in range(3)]
        _respond(survey, users[0], q1="yes", q2="first")
        _respond(survey, users[1], q1="yes", q2="")
        _respond(survey, users[2], q1="no", q2="third")

        body = client.get(f"/api/surveys/{survey.id}/results/").json()
        assert body["total_responses"] == 3
        by_id = {q["id"]: q for q in body["questions"]}
        assert by_id["q1"]["distribution"] == {"yes": 2, "no": 1}
        assert by_id["q1"]["answer_count"] == 3
        # Empty string answers are excluded.
        assert sorted(by_id["q2"]["values"]) == ["first", "third"]
        assert by_id["q2"]["answer_count"] == 2

    def test_empty_survey(self, client, survey):
        body = client.get(f"/api/surveys/{survey.id}/results/").json()
        assert body["total_responses"] == 0
        assert all(q["answer_count"] == 0 for q in body["questions"])
