# tests/api/routes/syndarix/test_issues.py
"""
Comprehensive tests for the Issues API endpoints.

Tests cover:
- CRUD operations (create, read, update, delete)
- Issue filtering and search
- Issue assignment
- Issue statistics
- Authorization checks
"""

import uuid

import pytest
import pytest_asyncio
from fastapi import status


@pytest_asyncio.fixture
async def test_project(client, user_token):
    """Create a test project for issue tests."""
    response = await client.post(
        "/api/v1/projects",
        json={"name": "Issue Test Project", "slug": "issue-test-project"},
        headers={"Authorization": f"Bearer {user_token}"},
    )
    return response.json()


@pytest_asyncio.fixture
async def superuser_project(client, superuser_token):
    """Create a project owned by superuser."""
    response = await client.post(
        "/api/v1/projects",
        json={"name": "Superuser Project", "slug": "superuser-project"},
        headers={"Authorization": f"Bearer {superuser_token}"},
    )
    return response.json()


@pytest.mark.asyncio
class TestCreateIssue:
    """Tests for POST /api/v1/projects/{project_id}/issues endpoint."""

    async def test_create_issue_success(self, client, user_token, test_project):
        """Test successful issue creation."""
        project_id = test_project["id"]

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Test Issue",
                "body": "This is a test issue description",
                "priority": "medium",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_201_CREATED
        data = response.json()

        assert data["title"] == "Test Issue"
        assert data["body"] == "This is a test issue description"
        assert data["priority"] == "medium"
        assert data["status"] == "open"
        assert data["project_id"] == project_id
        assert "id" in data
        assert "created_at" in data

    async def test_create_issue_minimal_fields(self, client, user_token, test_project):
        """Test creating issue with only required fields."""
        project_id = test_project["id"]

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Minimal Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_201_CREATED
        data = response.json()
        assert data["title"] == "Minimal Issue"
        assert data["body"] == ""  # Body defaults to empty string
        assert data["status"] == "open"

    async def test_create_issue_with_labels(self, client, user_token, test_project):
        """Test creating issue with labels."""
        project_id = test_project["id"]

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Labeled Issue",
                "labels": ["bug", "urgent", "frontend"],
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_201_CREATED
        data = response.json()
        assert "bug" in data["labels"]
        assert "urgent" in data["labels"]
        assert "frontend" in data["labels"]

    async def test_create_issue_with_story_points(self, client, user_token, test_project):
        """Test creating issue with story points."""
        project_id = test_project["id"]

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Story Points Issue",
                "story_points": 5,
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_201_CREATED
        data = response.json()
        assert data["story_points"] == 5

    async def test_create_issue_unauthorized_project(
        self, client, user_token, superuser_project
    ):
        """Test that users cannot create issues in others' projects."""
        project_id = superuser_project["id"]

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Unauthorized Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_403_FORBIDDEN

    async def test_create_issue_nonexistent_project(self, client, user_token):
        """Test creating issue in nonexistent project."""
        fake_project_id = str(uuid.uuid4())

        response = await client.post(
            f"/api/v1/projects/{fake_project_id}/issues",
            json={
                "project_id": fake_project_id,
                "title": "Orphan Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
class TestListIssues:
    """Tests for GET /api/v1/projects/{project_id}/issues endpoint."""

    async def test_list_issues_empty(self, client, user_token, test_project):
        """Test listing issues when none exist."""
        project_id = test_project["id"]

        response = await client.get(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert data["data"] == []
        assert data["pagination"]["total"] == 0

    async def test_list_issues_with_data(self, client, user_token, test_project):
        """Test listing issues returns created issues."""
        project_id = test_project["id"]

        # Create multiple issues
        for i in range(3):
            await client.post(
                f"/api/v1/projects/{project_id}/issues",
                json={
                    "project_id": project_id,
                    "title": f"Issue {i + 1}",
                },
                headers={"Authorization": f"Bearer {user_token}"},
            )

        response = await client.get(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert len(data["data"]) == 3
        assert data["pagination"]["total"] == 3

    async def test_list_issues_filter_by_status(self, client, user_token, test_project):
        """Test filtering issues by status."""
        project_id = test_project["id"]

        # Create issues with different statuses
        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Open Issue",
                "status": "open",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Closed Issue",
                "status": "closed",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        # Filter by open
        response = await client.get(
            f"/api/v1/projects/{project_id}/issues?status=open",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert len(data["data"]) == 1
        assert data["data"][0]["status"] == "open"

    async def test_list_issues_filter_by_priority(self, client, user_token, test_project):
        """Test filtering issues by priority."""
        project_id = test_project["id"]

        # Create issues with different priorities
        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "High Priority Issue",
                "priority": "high",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Low Priority Issue",
                "priority": "low",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        # Filter by high priority
        response = await client.get(
            f"/api/v1/projects/{project_id}/issues?priority=high",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert len(data["data"]) == 1
        assert data["data"][0]["priority"] == "high"

    async def test_list_issues_search(self, client, user_token, test_project):
        """Test searching issues by title/body."""
        project_id = test_project["id"]

        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Authentication Bug",
                "body": "Users cannot login",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "UI Enhancement",
                "body": "Improve dashboard layout",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        # Search for authentication
        response = await client.get(
            f"/api/v1/projects/{project_id}/issues?search=authentication",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert len(data["data"]) == 1
        assert "Authentication" in data["data"][0]["title"]

    async def test_list_issues_pagination(self, client, user_token, test_project):
        """Test pagination works correctly."""
        project_id = test_project["id"]

        # Create 5 issues
        for i in range(5):
            await client.post(
                f"/api/v1/projects/{project_id}/issues",
                json={
                    "project_id": project_id,
                    "title": f"Issue {i + 1}",
                },
                headers={"Authorization": f"Bearer {user_token}"},
            )

        # Get first page (2 items)
        response = await client.get(
            f"/api/v1/projects/{project_id}/issues?page=1&limit=2",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert len(data["data"]) == 2
        assert data["pagination"]["total"] == 5
        assert data["pagination"]["page"] == 1


@pytest.mark.asyncio
class TestGetIssue:
    """Tests for GET /api/v1/projects/{project_id}/issues/{issue_id} endpoint."""

    async def test_get_issue_success(self, client, user_token, test_project):
        """Test getting an issue by ID."""
        project_id = test_project["id"]

        # Create issue
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Get Test Issue",
                "body": "Test description",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Get issue
        response = await client.get(
            f"/api/v1/projects/{project_id}/issues/{issue_id}",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert data["id"] == issue_id
        assert data["title"] == "Get Test Issue"

    async def test_get_issue_not_found(self, client, user_token, test_project):
        """Test getting a nonexistent issue."""
        project_id = test_project["id"]
        fake_issue_id = str(uuid.uuid4())

        response = await client.get(
            f"/api/v1/projects/{project_id}/issues/{fake_issue_id}",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
class TestUpdateIssue:
    """Tests for PATCH /api/v1/projects/{project_id}/issues/{issue_id} endpoint."""

    async def test_update_issue_success(self, client, user_token, test_project):
        """Test updating an issue."""
        project_id = test_project["id"]

        # Create issue
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Original Title",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Update issue
        response = await client.patch(
            f"/api/v1/projects/{project_id}/issues/{issue_id}",
            json={"title": "Updated Title", "body": "New description"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert data["title"] == "Updated Title"
        assert data["body"] == "New description"

    async def test_update_issue_status(self, client, user_token, test_project):
        """Test updating issue status."""
        project_id = test_project["id"]

        # Create issue
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Status Test Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Update status to in_progress
        response = await client.patch(
            f"/api/v1/projects/{project_id}/issues/{issue_id}",
            json={"status": "in_progress"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.json()["status"] == "in_progress"

    async def test_update_issue_priority(self, client, user_token, test_project):
        """Test updating issue priority."""
        project_id = test_project["id"]

        # Create issue with low priority
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Priority Test Issue",
                "priority": "low",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Update to critical
        response = await client.patch(
            f"/api/v1/projects/{project_id}/issues/{issue_id}",
            json={"priority": "critical"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.json()["priority"] == "critical"

    async def test_update_issue_not_found(self, client, user_token, test_project):
        """Test updating a nonexistent issue."""
        project_id = test_project["id"]
        fake_issue_id = str(uuid.uuid4())

        response = await client.patch(
            f"/api/v1/projects/{project_id}/issues/{fake_issue_id}",
            json={"title": "Updated Title"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
class TestDeleteIssue:
    """Tests for DELETE /api/v1/projects/{project_id}/issues/{issue_id} endpoint."""

    async def test_delete_issue_success(self, client, user_token, test_project):
        """Test deleting an issue."""
        project_id = test_project["id"]

        # Create issue
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Delete Test Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Delete issue
        response = await client.delete(
            f"/api/v1/projects/{project_id}/issues/{issue_id}",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        assert response.json()["success"] is True

    async def test_delete_issue_not_found(self, client, user_token, test_project):
        """Test deleting a nonexistent issue."""
        project_id = test_project["id"]
        fake_issue_id = str(uuid.uuid4())

        response = await client.delete(
            f"/api/v1/projects/{project_id}/issues/{fake_issue_id}",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
class TestIssueStats:
    """Tests for GET /api/v1/projects/{project_id}/issues/stats endpoint."""

    async def test_get_issue_stats_empty(self, client, user_token, test_project):
        """Test getting stats when no issues exist."""
        project_id = test_project["id"]

        response = await client.get(
            f"/api/v1/projects/{project_id}/issues/stats",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert data["total"] == 0
        assert data["open"] == 0
        assert data["in_progress"] == 0
        assert data["in_review"] == 0
        assert data["blocked"] == 0
        assert data["closed"] == 0

    async def test_get_issue_stats_with_data(self, client, user_token, test_project):
        """Test getting stats with issues."""
        project_id = test_project["id"]

        # Create issues with different statuses and priorities
        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Open High Issue",
                "status": "open",
                "priority": "high",
                "story_points": 5,
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Closed Low Issue",
                "status": "closed",
                "priority": "low",
                "story_points": 3,
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        response = await client.get(
            f"/api/v1/projects/{project_id}/issues/stats",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert data["total"] == 2
        assert data["open"] == 1
        assert data["closed"] == 1
        assert data["by_priority"]["high"] == 1
        assert data["by_priority"]["low"] == 1


@pytest.mark.asyncio
class TestIssueAuthorization:
    """Tests for issue authorization."""

    async def test_superuser_can_manage_any_project_issues(
        self, client, user_token, superuser_token, test_project
    ):
        """Test that superuser can manage issues in any project."""
        project_id = test_project["id"]

        # Create issue as superuser in user's project
        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Superuser Issue",
            },
            headers={"Authorization": f"Bearer {superuser_token}"},
        )

        assert response.status_code == status.HTTP_201_CREATED

    async def test_user_cannot_access_other_project_issues(
        self, client, user_token, superuser_project
    ):
        """Test that users cannot access issues in others' projects."""
        project_id = superuser_project["id"]

        response = await client.get(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_403_FORBIDDEN


@pytest.mark.asyncio
class TestIssueAssignment:
    """Tests for issue assignment endpoints."""

    async def test_assign_issue_to_human(self, client, user_token, test_project):
        """Test assigning an issue to a human."""
        project_id = test_project["id"]

        # Create issue
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue to Assign",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Assign to human
        response = await client.post(
            f"/api/v1/projects/{project_id}/issues/{issue_id}/assign",
            json={"human_assignee": "john.doe@example.com"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        assert data["human_assignee"] == "john.doe@example.com"

    async def test_unassign_issue(self, client, user_token, test_project):
        """Test unassigning an issue."""
        project_id = test_project["id"]

        # Create issue and assign
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue to Unassign",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        await client.post(
            f"/api/v1/projects/{project_id}/issues/{issue_id}/assign",
            json={"human_assignee": "john.doe@example.com"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        # Unassign
        response = await client.delete(
            f"/api/v1/projects/{project_id}/issues/{issue_id}/assignment",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK
        data = response.json()
        # After unassign, assigned_agent_id should be None
        # Note: human_assignee may or may not be cleared depending on implementation
        assert data["assigned_agent_id"] is None

    async def test_assign_issue_not_found(self, client, user_token, test_project):
        """Test assigning a nonexistent issue."""
        project_id = test_project["id"]
        fake_issue_id = str(uuid.uuid4())

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues/{fake_issue_id}/assign",
            json={"human_assignee": "john.doe@example.com"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND

    async def test_unassign_issue_not_found(self, client, user_token, test_project):
        """Test unassigning a nonexistent issue."""
        project_id = test_project["id"]
        fake_issue_id = str(uuid.uuid4())

        response = await client.delete(
            f"/api/v1/projects/{project_id}/issues/{fake_issue_id}/assignment",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND

    async def test_assign_issue_clears_assignment(self, client, user_token, test_project):
        """Test that assigning to null clears both assignments."""
        project_id = test_project["id"]

        # Create issue and assign
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue to Clear",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        await client.post(
            f"/api/v1/projects/{project_id}/issues/{issue_id}/assign",
            json={"human_assignee": "john.doe@example.com"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        # Clear assignment by sending empty object
        response = await client.post(
            f"/api/v1/projects/{project_id}/issues/{issue_id}/assign",
            json={},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_200_OK


@pytest.mark.asyncio
class TestIssueSync:
    """Tests for issue sync endpoint."""

    async def test_sync_issue_no_tracker(self, client, user_token, test_project):
        """Test syncing an issue without external tracker."""
        project_id = test_project["id"]

        # Create issue without external tracker
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue without Tracker",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Try to sync
        response = await client.post(
            f"/api/v1/projects/{project_id}/issues/{issue_id}/sync",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        # Should fail because no external tracker configured
        assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY

    async def test_sync_issue_not_found(self, client, user_token, test_project):
        """Test syncing a nonexistent issue."""
        project_id = test_project["id"]
        fake_issue_id = str(uuid.uuid4())

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues/{fake_issue_id}/sync",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
class TestIssueCrossProjectValidation:
    """Tests for cross-project validation (IDOR prevention)."""

    async def test_issue_not_in_project(self, client, user_token):
        """Test accessing issue that exists but not in the specified project."""
        # Create two projects
        project1 = await client.post(
            "/api/v1/projects",
            json={"name": "Project 1", "slug": "project-1-idor"},
            headers={"Authorization": f"Bearer {user_token}"},
        )
        project2 = await client.post(
            "/api/v1/projects",
            json={"name": "Project 2", "slug": "project-2-idor"},
            headers={"Authorization": f"Bearer {user_token}"},
        )
        project1_id = project1.json()["id"]
        project2_id = project2.json()["id"]

        # Create issue in project1
        issue_response = await client.post(
            f"/api/v1/projects/{project1_id}/issues",
            json={
                "project_id": project1_id,
                "title": "Project 1 Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = issue_response.json()["id"]

        # Try to access issue via project2 (IDOR attempt)
        response = await client.get(
            f"/api/v1/projects/{project2_id}/issues/{issue_id}",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND

    async def test_update_issue_wrong_project(self, client, user_token):
        """Test updating issue through wrong project."""
        # Create two projects
        project1 = await client.post(
            "/api/v1/projects",
            json={"name": "Project A", "slug": "project-a-idor"},
            headers={"Authorization": f"Bearer {user_token}"},
        )
        project2 = await client.post(
            "/api/v1/projects",
            json={"name": "Project B", "slug": "project-b-idor"},
            headers={"Authorization": f"Bearer {user_token}"},
        )
        project1_id = project1.json()["id"]
        project2_id = project2.json()["id"]

        # Create issue in project1
        issue_response = await client.post(
            f"/api/v1/projects/{project1_id}/issues",
            json={
                "project_id": project1_id,
                "title": "Project A Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = issue_response.json()["id"]

        # Try to update issue via project2 (IDOR attempt)
        response = await client.patch(
            f"/api/v1/projects/{project2_id}/issues/{issue_id}",
            json={"title": "Hacked Title"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND

    async def test_delete_issue_wrong_project(self, client, user_token):
        """Test deleting issue through wrong project."""
        # Create two projects
        project1 = await client.post(
            "/api/v1/projects",
            json={"name": "Project X", "slug": "project-x-idor"},
            headers={"Authorization": f"Bearer {user_token}"},
        )
        project2 = await client.post(
            "/api/v1/projects",
            json={"name": "Project Y", "slug": "project-y-idor"},
            headers={"Authorization": f"Bearer {user_token}"},
        )
        project1_id = project1.json()["id"]
        project2_id = project2.json()["id"]

        # Create issue in project1
        issue_response = await client.post(
            f"/api/v1/projects/{project1_id}/issues",
            json={
                "project_id": project1_id,
                "title": "Project X Issue",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = issue_response.json()["id"]

        # Try to delete issue via project2 (IDOR attempt)
        response = await client.delete(
            f"/api/v1/projects/{project2_id}/issues/{issue_id}",
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND


@pytest.mark.asyncio
class TestIssueValidation:
    """Tests for issue validation during create/update."""

    async def test_create_issue_invalid_priority(self, client, user_token, test_project):
        """Test creating issue with invalid priority."""
        project_id = test_project["id"]

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue with Invalid Priority",
                "priority": "invalid_priority",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY

    async def test_create_issue_invalid_status(self, client, user_token, test_project):
        """Test creating issue with invalid status."""
        project_id = test_project["id"]

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue with Invalid Status",
                "status": "invalid_status",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY

    async def test_update_issue_invalid_priority(self, client, user_token, test_project):
        """Test updating issue with invalid priority."""
        project_id = test_project["id"]

        # Create issue
        create_response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue to Update",
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )
        issue_id = create_response.json()["id"]

        # Update with invalid priority
        response = await client.patch(
            f"/api/v1/projects/{project_id}/issues/{issue_id}",
            json={"priority": "invalid_priority"},
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY

    async def test_create_issue_with_nonexistent_sprint(
        self, client, user_token, test_project
    ):
        """Test creating issue with nonexistent sprint ID."""
        project_id = test_project["id"]
        fake_sprint_id = str(uuid.uuid4())

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue with Fake Sprint",
                "sprint_id": fake_sprint_id,
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND

    async def test_create_issue_with_nonexistent_agent(
        self, client, user_token, test_project
    ):
        """Test creating issue with nonexistent agent ID."""
        project_id = test_project["id"]
        fake_agent_id = str(uuid.uuid4())

        response = await client.post(
            f"/api/v1/projects/{project_id}/issues",
            json={
                "project_id": project_id,
                "title": "Issue with Fake Agent",
                "assigned_agent_id": fake_agent_id,
            },
            headers={"Authorization": f"Bearer {user_token}"},
        )

        assert response.status_code == status.HTTP_404_NOT_FOUND
