"""Tests for V3 Studies API."""

import pytest
from pytest_httpx import HTTPXMock

from concentriq import ConcentriqClient
from concentriq.auth import ApiKeyAuth
from concentriq.exceptions import NotFoundError, ValidationError


class TestStudiesList:
    """Tests for Studies.list() behavior."""

    def test_list_returns_studies(self, httpx_mock: HTTPXMock):
        """List should return all studies."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies",
            json={
                "items": [
                    {"id": 1, "name": "Study A", "description": "First study"},
                    {"id": 2, "name": "Study B", "description": "Second study"},
                ],
                "total": 2,
            },
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.list()

        assert "items" in result
        assert len(result["items"]) == 2
        assert result["items"][0]["name"] == "Study A"


class TestStudiesGet:
    """Tests for Studies.get() behavior."""

    def test_get_returns_single_study(self, httpx_mock: HTTPXMock):
        """Get should return a single study by ID."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123",
            json={
                "id": 123,
                "name": "Study A",
                "description": "First study",
                "createdAt": "2024-01-01T00:00:00Z",
            },
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.get(id=123)

        assert result["id"] == 123
        assert result["name"] == "Study A"

    def test_get_raises_not_found_for_invalid_id(self, httpx_mock: HTTPXMock):
        """Get should raise NotFoundError for non-existent study."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/999999",
            status_code=404,
            json={"error": "Study not found"},
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )

        with pytest.raises(NotFoundError):
            client.v3.studies.get(id=999999)


class TestStudiesCreate:
    """Tests for Studies.create() behavior."""

    def test_create_returns_created_study(self, httpx_mock: HTTPXMock):
        """Create should return the newly created study."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies",
            method="POST",
            status_code=201,
            json={"id": 456, "name": "New Study", "description": "Created study"},
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.create(
            {"name": "New Study", "description": "Created study"}
        )

        assert result["id"] == 456
        assert result["name"] == "New Study"

    def test_create_raises_validation_error_on_missing_name(
        self, httpx_mock: HTTPXMock
    ):
        """Create should raise ValidationError when name is missing."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies",
            method="POST",
            status_code=400,
            json={"error": "name is required"},
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )

        with pytest.raises(ValidationError):
            client.v3.studies.create({"description": "No name"})


class TestStudiesUpdate:
    """Tests for Studies.update() behavior."""

    def test_update_returns_updated_study(self, httpx_mock: HTTPXMock):
        """Update should return the updated study."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123",
            method="PUT",
            json={"id": 123, "name": "Updated Study", "description": "Updated desc"},
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.update(
            id=123, data={"name": "Updated Study", "description": "Updated desc"}
        )

        assert result["id"] == 123
        assert result["name"] == "Updated Study"

    def test_update_raises_not_found_for_invalid_id(self, httpx_mock: HTTPXMock):
        """Update should raise NotFoundError for non-existent study."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/999999",
            method="PUT",
            status_code=404,
            json={"error": "Study not found"},
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )

        with pytest.raises(NotFoundError):
            client.v3.studies.update(id=999999, data={"name": "New Name"})


class TestStudiesDelete:
    """Tests for Studies.delete() behavior."""

    def test_delete_returns_success(self, httpx_mock: HTTPXMock):
        """Delete should complete successfully."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123",
            method="DELETE",
            status_code=204,
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.delete(id=123)

        assert result is None

    def test_delete_raises_not_found_for_invalid_id(self, httpx_mock: HTTPXMock):
        """Delete should raise NotFoundError for non-existent study."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/999999",
            method="DELETE",
            status_code=404,
            json={"error": "Study not found"},
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )

        with pytest.raises(NotFoundError):
            client.v3.studies.delete(id=999999)


class TestStudiesGetFields:
    """Tests for Studies.get_fields() behavior."""

    def test_get_fields_returns_study_fields(self, httpx_mock: HTTPXMock):
        """Get fields should return list of fields in the study."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123/fields",
            json=[
                {"id": 1, "name": "Field A", "type": "text"},
                {"id": 2, "name": "Field B", "type": "number"},
            ],
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.get_fields(study_id=123)

        assert isinstance(result, list)
        assert len(result) == 2
        assert result[0]["name"] == "Field A"


class TestStudiesAddField:
    """Tests for Studies.add_field() behavior."""

    def test_add_field_returns_success(self, httpx_mock: HTTPXMock):
        """Add field should complete successfully."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123/fields/456",
            method="POST",
            status_code=200,
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.add_field(study_id=123, field_id=456)

        assert result is None


class TestStudiesRemoveField:
    """Tests for Studies.remove_field() behavior."""

    def test_remove_field_returns_success(self, httpx_mock: HTTPXMock):
        """Remove field should complete successfully."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123/fields/456",
            method="DELETE",
            status_code=200,
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.remove_field(study_id=123, field_id=456)

        assert result is None


class TestStudiesGetUsers:
    """Tests for Studies.get_users() behavior."""

    def test_get_users_returns_study_users(self, httpx_mock: HTTPXMock):
        """Get users should return list of users in the study."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123/users",
            json=[
                {"userId": 10, "role": "participant"},
                {"userId": 20, "role": "admin"},
            ],
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.get_users(study_id=123)

        assert isinstance(result, list)
        assert len(result) == 2
        assert result[0]["userId"] == 10


class TestStudiesUpsertUser:
    """Tests for Studies.upsert_user() behavior."""

    def test_upsert_user_returns_success(self, httpx_mock: HTTPXMock):
        """Upsert user should complete successfully."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123/users/456",
            method="PUT",
            status_code=200,
            json={"userId": 456, "role": "participant"},
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.upsert_user(
            study_id=123, user_id=456, data={"role": "participant"}
        )

        assert result["userId"] == 456
        assert result["role"] == "participant"


class TestStudiesRemoveUser:
    """Tests for Studies.remove_user() behavior."""

    def test_remove_user_returns_success(self, httpx_mock: HTTPXMock):
        """Remove user should complete successfully."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123/users/456",
            method="DELETE",
            status_code=200,
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.remove_user(study_id=123, user_id=456)

        assert result is None


class TestStudiesGetStatistics:
    """Tests for Studies.get_statistics() behavior."""

    def test_get_statistics_returns_study_stats(self, httpx_mock: HTTPXMock):
        """Get statistics should return study statistics."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/v3/studies/123/statistics",
            json=[
                {
                    "studyId": 123,
                    "userId": 10,
                    "resourceType": "Image",
                    "responseCount": 50,
                    "fieldsCount": 5,
                    "resourceCount": 100,
                },
            ],
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v3.studies.get_statistics(study_id=123)

        assert isinstance(result, list)
        assert len(result) == 1
        assert result[0]["studyId"] == 123
        assert result[0]["responseCount"] == 50
