"""Tests for production error and issue group endpoints."""

from unittest.mock import patch

_DB = "api.routers.errors.db"
_STORAGE = "api.routers.errors.storage"

# Valid UUIDs for path parameters that now require UUID validation
_ERR_ID = "00000000-0000-4000-8000-000000000001"
_ERR_ID_2 = "00000000-0000-4000-8000-000000000002"
_GRP_ID = "00000000-0000-4000-8000-000000000010"
_GRP_ID_2 = "00000000-0000-4000-8000-000000000020"
_MEMBER_ID = "00000000-0000-4000-8000-000000000100"
_MERGE_ID = "00000000-0000-4000-8000-000000001000"


class TestCreateProdError:
    """Tests for POST /v1/prod-errors."""

    def test_create_prod_error_success(self, client, auth_header):
        with patch(f"{_DB}.create_prod_error") as mock_create, \
             patch(f"{_STORAGE}.upload_prod_error", create=True):
            mock_create.return_value = None
            response = client.post(
                "/v1/prod-errors",
                content=b'{"error_id": "err_123", "exception": {"type": "ValueError"}}',
                headers={**auth_header, "content-type": "application/json"},
            )
            assert response.status_code == 200
            data = response.json()
            assert data["error_id"] == "err_123"
            assert data["status"] == "captured"

    def test_create_prod_error_auto_id(self, client, auth_header):
        with patch(f"{_DB}.create_prod_error") as mock_create, \
             patch(f"{_STORAGE}.upload_prod_error", create=True):
            mock_create.return_value = None
            response = client.post(
                "/v1/prod-errors",
                content=b'{"exception": {"type": "TypeError"}}',
                headers={**auth_header, "content-type": "application/json"},
            )
            assert response.status_code == 200
            data = response.json()
            assert "error_id" in data
            assert data["status"] == "captured"

    def test_create_prod_error_unauthorized(self, client):
        response = client.post(
            "/v1/prod-errors",
            content=b'{"error_id": "err_123"}',
            headers={"content-type": "application/json"},
        )
        assert response.status_code == 401


class TestListProdErrors:
    """Tests for GET /v1/prod-errors."""

    def test_list_prod_errors_success(self, client, auth_header):
        with patch(f"{_DB}.list_prod_errors") as mock_list:
            mock_list.return_value = {
                "errors": [
                    {
                        "error_id": _ERR_ID,
                        "error_data": {
                            "timestamp": 1700000000.0,
                            "exception": {"type": "ValueError", "message": "bad value"},
                            "request": {"url": "/api/test", "method": "GET"},
                            "environment": "production",
                        },
                        "created_at": "2025-01-15T10:00:00Z",
                    },
                ],
                "total": 1,
            }
            response = client.get("/v1/prod-errors", headers=auth_header)
            assert response.status_code == 200
            data = response.json()
            assert data["total"] == 1
            assert len(data["errors"]) == 1
            assert data["errors"][0]["exception_type"] == "ValueError"

    def test_list_prod_errors_unauthorized(self, client):
        response = client.get("/v1/prod-errors")
        assert response.status_code == 401


class TestGetProdError:
    """Tests for GET /v1/prod-errors/{error_id}."""

    def test_get_prod_error_success(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get:
            mock_get.return_value = {
                "error_data": {
                    "error_id": _ERR_ID,
                    "exception": {"type": "ValueError", "message": "test"},
                },
            }
            response = client.get(f"/v1/prod-errors/{_ERR_ID}", headers=auth_header)
            assert response.status_code == 200
            data = response.json()
            assert data["error_id"] == _ERR_ID

    def test_get_prod_error_not_found(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get, \
             patch(f"{_STORAGE}.download_prod_error", create=True) as mock_storage:
            mock_get.return_value = None
            mock_storage.return_value = None
            response = client.get(f"/v1/prod-errors/{_ERR_ID}", headers=auth_header)
            assert response.status_code == 404

    def test_get_prod_error_invalid_id(self, client, auth_header):
        response = client.get("/v1/prod-errors/not-a-uuid", headers=auth_header)
        assert response.status_code == 400

    def test_get_prod_error_unauthorized(self, client):
        response = client.get(f"/v1/prod-errors/{_ERR_ID}")
        assert response.status_code == 401


class TestDeleteProdError:
    """Tests for DELETE /v1/prod-errors/{error_id}."""

    def test_delete_prod_error_success(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get, \
             patch(f"{_DB}.delete_prod_error") as mock_delete, \
             patch(f"{_STORAGE}.delete_prod_error", create=True):
            mock_get.return_value = {"error_id": _ERR_ID}
            mock_delete.return_value = None
            response = client.delete(f"/v1/prod-errors/{_ERR_ID}", headers=auth_header)
            assert response.status_code == 200
            assert response.json()["status"] == "deleted"

    def test_delete_prod_error_not_found(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get:
            mock_get.return_value = None
            response = client.delete(f"/v1/prod-errors/{_ERR_ID}", headers=auth_header)
            assert response.status_code == 404

    def test_delete_prod_error_unauthorized(self, client):
        response = client.delete(f"/v1/prod-errors/{_ERR_ID}")
        assert response.status_code == 401


class TestSimilarErrors:
    """Tests for GET /v1/prod-errors/{error_id}/similar."""

    def test_get_similar_errors_success(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get, \
             patch(f"{_DB}.get_error_embedding") as mock_embed, \
             patch(f"{_DB}.search_similar_errors") as mock_search:
            mock_get.return_value = {"error_id": _ERR_ID}
            mock_embed.return_value = {"embedding": [0.1, 0.2, 0.3]}
            mock_search.return_value = [
                {"error_id": _ERR_ID_2, "similarity": 0.92},
            ]
            response = client.get(
                f"/v1/prod-errors/{_ERR_ID}/similar", headers=auth_header,
            )
            assert response.status_code == 200
            data = response.json()
            assert data["error_id"] == _ERR_ID
            assert len(data["matches"]) == 1

    def test_get_similar_no_embedding(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get, \
             patch(f"{_DB}.get_error_embedding") as mock_embed:
            mock_get.return_value = {"error_id": _ERR_ID}
            mock_embed.return_value = None
            response = client.get(
                f"/v1/prod-errors/{_ERR_ID}/similar", headers=auth_header,
            )
            assert response.status_code == 200
            assert response.json()["matches"] == []

    def test_get_similar_unauthorized(self, client):
        response = client.get(f"/v1/prod-errors/{_ERR_ID}/similar")
        assert response.status_code == 401


class TestGroupError:
    """Tests for POST /v1/prod-errors/{error_id}/group."""

    def test_group_error_success(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get, \
             patch(f"{_DB}.get_error_embedding") as mock_embed, \
             patch(f"{_DB}.search_similar_errors") as mock_search, \
             patch(f"{_DB}.create_issue_group") as mock_create, \
             patch(f"{_DB}.add_issue_group_member") as mock_add:
            mock_get.return_value = {
                "error_id": _ERR_ID,
                "error_data": {"exception": {"type": "ValueError"}},
            }
            mock_embed.return_value = {"embedding": [0.1, 0.2]}
            mock_search.return_value = [
                {"error_id": _ERR_ID_2, "similarity": 0.85},
            ]
            mock_create.return_value = {"id": _GRP_ID, "title": "ValueError"}
            mock_add.return_value = None
            response = client.post(
                f"/v1/prod-errors/{_ERR_ID}/group", headers=auth_header,
            )
            assert response.status_code == 200
            data = response.json()
            assert "group" in data
            assert "members" in data

    def test_group_error_no_embedding(self, client, auth_header):
        with patch(f"{_DB}.get_prod_error") as mock_get, \
             patch(f"{_DB}.get_error_embedding") as mock_embed:
            mock_get.return_value = {"error_id": _ERR_ID}
            mock_embed.return_value = None
            response = client.post(
                f"/v1/prod-errors/{_ERR_ID}/group", headers=auth_header,
            )
            assert response.status_code == 400

    def test_group_error_unauthorized(self, client):
        response = client.post(f"/v1/prod-errors/{_ERR_ID}/group")
        assert response.status_code == 401


class TestIssueGroups:
    """Tests for issue group CRUD endpoints."""

    def test_list_issue_groups(self, client, auth_header):
        with patch(f"{_DB}.list_issue_groups") as mock_list, \
             patch(f"{_DB}.count_members_by_groups") as mock_counts:
            mock_list.return_value = {
                "groups": [{"id": _GRP_ID, "title": "ValueError group"}],
                "total": 1,
            }
            mock_counts.return_value = {_GRP_ID: 5}
            response = client.get("/v1/issue-groups", headers=auth_header)
            assert response.status_code == 200
            data = response.json()
            assert len(data["groups"]) == 1
            assert data["groups"][0]["member_count"] == 5
            assert data["total"] == 1
            assert data["page"] == 1

    def test_get_issue_group_detail(self, client, auth_header):
        with patch(f"{_DB}.get_issue_group") as mock_get:
            mock_get.return_value = {
                "id": _GRP_ID, "title": "ValueError group",
                "org_id": "org_test456",
            }
            response = client.get(f"/v1/issue-groups/{_GRP_ID}", headers=auth_header)
            assert response.status_code == 200

    def test_get_issue_group_not_found(self, client, auth_header):
        with patch(f"{_DB}.get_issue_group") as mock_get:
            mock_get.return_value = None
            response = client.get(f"/v1/issue-groups/{_GRP_ID}", headers=auth_header)
            assert response.status_code == 404

    def test_get_issue_group_invalid_id(self, client, auth_header):
        response = client.get("/v1/issue-groups/not-a-uuid", headers=auth_header)
        assert response.status_code == 400

    def test_delete_issue_group(self, client, auth_header):
        with patch(f"{_DB}.get_issue_group") as mock_get, \
             patch(f"{_DB}.delete_issue_group") as mock_delete:
            mock_get.return_value = {"id": _GRP_ID, "org_id": "org_test456"}
            mock_delete.return_value = None
            response = client.delete(f"/v1/issue-groups/{_GRP_ID}", headers=auth_header)
            assert response.status_code == 200
            assert response.json()["status"] == "deleted"

    def test_issue_group_stats(self, client, auth_header):
        with patch(f"{_DB}.get_issue_group_stats") as mock_stats:
            mock_stats.return_value = {
                "total_groups": 5,
                "total_members": 42,
            }
            response = client.get("/v1/issue-groups/stats", headers=auth_header)
            assert response.status_code == 200

    def test_issue_groups_unauthorized(self, client):
        response = client.get("/v1/issue-groups")
        assert response.status_code == 401
