"""Tests for Templates client."""

import pytest
from pytest_httpx import HTTPXMock

from concentriq import ConcentriqClient
from concentriq.auth import ApiKeyAuth


class TestTemplatesList:
    """Tests for Templates.list() behavior."""

    def test_list_returns_dict_of_templates(self, httpx_mock: HTTPXMock):
        """List should return a dictionary of template data keyed by ID."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates",
            json={
                "meta": {"status": 200},
                "data": {
                    "templates": {
                        "1": {
                            "id": 1,
                            "name": "Clinical Template",
                            "description": "Template for clinical data",
                            "ownerId": 100,
                            "ownerName": "Dr. Smith",
                            "moduleId": 5,
                            "isDefault": True,
                            "lastModified": "2024-01-15T10:30:00Z",
                            "created": "2024-01-01T09:00:00Z",
                        },
                        "2": {
                            "id": 2,
                            "name": "Research Template",
                            "description": "Template for research data",
                            "ownerId": 101,
                            "ownerName": "Dr. Jones",
                            "moduleId": 6,
                            "isDefault": False,
                            "lastModified": "2024-01-20T14:00:00Z",
                            "created": "2024-01-10T11:00:00Z",
                        },
                    }
                },
            },
        )

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

        assert isinstance(result, dict)
        assert len(result) == 2
        assert "1" in result
        assert "2" in result
        assert result["1"]["name"] == "Clinical Template"
        assert result["2"]["ownerId"] == 101

    def test_list_with_filters(self, httpx_mock: HTTPXMock):
        """List should support filters parameter."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates?filters=%7B%22name%22%3A+%5B%22Clinical%22%5D%2C+%22moduleId%22%3A+%5B5%5D%7D",
            json={
                "meta": {"status": 200},
                "data": {
                    "templates": {
                        "1": {
                            "id": 1,
                            "name": "Clinical Template",
                            "description": "Template for clinical data",
                        }
                    }
                },
            },
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v1.templates.list(filters={"name": ["Clinical"], "moduleId": [5]})

        assert isinstance(result, dict)
        assert len(result) == 1

    def test_list_returns_empty_dict_when_no_results(self, httpx_mock: HTTPXMock):
        """List should return empty dict when API returns no data."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates",
            json={"meta": {"status": 200}, "data": {"templates": {}}},
        )

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

        assert result == {}

    def test_list_raises_authentication_error_when_unauthorized(
        self, httpx_mock: HTTPXMock
    ):
        """List should raise AuthenticationError when API returns 401."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates",
            status_code=401,
            json={"error": "Unauthorized"},
        )

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

        from concentriq.exceptions import AuthenticationError

        with pytest.raises(AuthenticationError):
            client.v1.templates.list()


class TestTemplatesCreate:
    """Tests for Templates.create() behavior."""

    def test_create_new_template_returns_created_template(self, httpx_mock: HTTPXMock):
        """Create should return the newly created template data."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates",
            method="POST",
            json={
                "meta": {"status": 201},
                "data": {
                    "id": 456,
                    "name": "New Template",
                    "description": "A new template",
                    "ownerId": 100,
                    "ownerName": "Dr. Smith",
                    "moduleId": 5,
                    "isDefault": False,
                },
            },
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v1.templates.create(
            {"name": "New Template", "description": "A new template", "moduleId": 5}
        )

        assert result["id"] == 456
        assert result["name"] == "New Template"
        assert result["ownerId"] == 100

    def test_create_duplicate_template_returns_created_template(
        self, httpx_mock: HTTPXMock
    ):
        """Create should support duplicating existing template via cloneSourceId."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates",
            method="POST",
            json={
                "meta": {"status": 201},
                "data": {
                    "id": 789,
                    "name": "Cloned Template",
                    "description": "Original description",
                    "ownerId": 100,
                    "ownerName": "Dr. Smith",
                    "moduleId": 5,
                    "isDefault": False,
                },
            },
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v1.templates.create(
            {"cloneSourceId": 123, "name": "Cloned Template"}
        )

        assert result["id"] == 789
        assert result["name"] == "Cloned Template"

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

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

        from concentriq.exceptions import ValidationError

        with pytest.raises(ValidationError):
            client.v1.templates.create({})

    def test_create_raises_authentication_error_when_unauthorized(
        self, httpx_mock: HTTPXMock
    ):
        """Create should raise AuthenticationError when not authenticated."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates",
            method="POST",
            status_code=401,
            json={"error": "Unauthorized"},
        )

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

        from concentriq.exceptions import AuthenticationError

        with pytest.raises(AuthenticationError):
            client.v1.templates.create({"name": "Test"})


class TestTemplatesUpdate:
    """Tests for Templates.update() behavior."""

    def test_update_returns_updated_template(self, httpx_mock: HTTPXMock):
        """Update should return the updated template data."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates/123",
            method="PATCH",
            json={
                "meta": {"status": 200},
                "data": {
                    "id": 123,
                    "name": "Updated Template",
                    "description": "Updated description",
                    "ownerId": 100,
                    "ownerName": "Dr. Smith",
                    "moduleId": 5,
                    "isDefault": False,
                    "sharedWithOrganization": True,
                },
            },
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v1.templates.update(
            123, {"name": "Updated Template", "sharedWithOrganization": True}
        )

        assert result["id"] == 123
        assert result["name"] == "Updated Template"
        assert result["sharedWithOrganization"] is True

    def test_update_raises_not_found_for_invalid_id(self, httpx_mock: HTTPXMock):
        """Update should raise NotFoundError for non-existent template."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates/99999",
            method="PATCH",
            status_code=404,
            json={"error": "Template not found"},
        )

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

        from concentriq.exceptions import NotFoundError

        with pytest.raises(NotFoundError):
            client.v1.templates.update(99999, {"name": "Updated"})

    def test_update_raises_validation_error_on_invalid_data(
        self, httpx_mock: HTTPXMock
    ):
        """Update should raise ValidationError when data is invalid."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates/123",
            method="PATCH",
            status_code=400,
            json={"error": "Invalid data"},
        )

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

        from concentriq.exceptions import ValidationError

        with pytest.raises(ValidationError):
            client.v1.templates.update(123, {"invalid": "data"})

    def test_update_raises_authorization_error_when_forbidden(
        self, httpx_mock: HTTPXMock
    ):
        """Update should raise AuthorizationError when not authorized."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates/123",
            method="PATCH",
            status_code=403,
            json={"error": "You do not have permission to manage this template"},
        )

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

        from concentriq.exceptions import AuthorizationError

        with pytest.raises(AuthorizationError):
            client.v1.templates.update(123, {"name": "Updated"})


class TestTemplatesDelete:
    """Tests for Templates.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/templates/123",
            method="DELETE",
            json={
                "meta": {"status": 200},
                "data": {"success": "template: 123 successfully deleted."},
            },
        )

        client = ConcentriqClient(
            base_url="https://test.concentriq.com", auth=ApiKeyAuth("test-key")
        )
        result = client.v1.templates.delete(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 template."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates/99999",
            method="DELETE",
            status_code=404,
            json={"error": "Template not found"},
        )

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

        from concentriq.exceptions import NotFoundError

        with pytest.raises(NotFoundError):
            client.v1.templates.delete(99999)

    def test_delete_raises_authorization_error_when_forbidden(
        self, httpx_mock: HTTPXMock
    ):
        """Delete should raise AuthorizationError when not authorized."""
        httpx_mock.add_response(
            url="https://test.concentriq.com/api/templates/123",
            method="DELETE",
            status_code=403,
            json={"error": "You do not have permission to manage this template"},
        )

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

        from concentriq.exceptions import AuthorizationError

        with pytest.raises(AuthorizationError):
            client.v1.templates.delete(123)
