"""
Project and Agent E2E Workflow Tests.

Tests complete project management workflows with real PostgreSQL:
- Project CRUD and lifecycle management
- Agent spawning and lifecycle
- Issue management within projects
- Sprint planning and execution

Usage:
    make test-e2e          # Run all E2E tests
"""

from datetime import date, timedelta
from uuid import uuid4

import pytest

pytestmark = [
    pytest.mark.e2e,
    pytest.mark.postgres,
    pytest.mark.asyncio,
]


class TestProjectCRUDWorkflows:
    """Test complete project CRUD workflows."""

    async def test_create_project_workflow(self, e2e_client):
        """Test creating a project as authenticated user."""
        # Register and login
        email = f"project-owner-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Project",
                "last_name": "Owner",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        # Create project
        project_slug = f"test-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={
                "name": "E2E Test Project",
                "slug": project_slug,
                "description": "A project for E2E testing",
                "autonomy_level": "milestone",
            },
        )

        assert create_resp.status_code == 201, f"Failed: {create_resp.text}"
        project = create_resp.json()
        assert project["name"] == "E2E Test Project"
        assert project["slug"] == project_slug
        assert project["status"] == "active"
        assert project["agent_count"] == 0
        assert project["issue_count"] == 0

    async def test_list_projects_only_shows_owned(self, e2e_client):
        """Test that users only see their own projects."""
        # Create two users with projects
        users = []
        for i in range(2):
            email = f"user-{i}-{uuid4().hex[:8]}@example.com"
            password = "SecurePass123!"

            await e2e_client.post(
                "/api/v1/auth/register",
                json={
                    "email": email,
                    "password": password,
                    "first_name": f"User{i}",
                    "last_name": "Test",
                },
            )
            login_resp = await e2e_client.post(
                "/api/v1/auth/login",
                json={"email": email, "password": password},
            )
            tokens = login_resp.json()

            # Each user creates their own project
            project_slug = f"user{i}-project-{uuid4().hex[:8]}"
            await e2e_client.post(
                "/api/v1/projects",
                headers={"Authorization": f"Bearer {tokens['access_token']}"},
                json={
                    "name": f"User {i} Project",
                    "slug": project_slug,
                },
            )
            users.append({"email": email, "tokens": tokens, "slug": project_slug})

        # User 0 should only see their project
        list_resp = await e2e_client.get(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {users[0]['tokens']['access_token']}"},
        )
        assert list_resp.status_code == 200
        data = list_resp.json()
        slugs = [p["slug"] for p in data["data"]]
        assert users[0]["slug"] in slugs
        assert users[1]["slug"] not in slugs

    async def test_project_lifecycle_pause_resume(self, e2e_client):
        """Test pausing and resuming a project."""
        # Setup user and project
        email = f"lifecycle-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Lifecycle",
                "last_name": "Test",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        project_slug = f"lifecycle-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Lifecycle Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Pause the project
        pause_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/pause",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert pause_resp.status_code == 200
        assert pause_resp.json()["status"] == "paused"

        # Resume the project
        resume_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/resume",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert resume_resp.status_code == 200
        assert resume_resp.json()["status"] == "active"

    async def test_project_archive(self, e2e_client):
        """Test archiving a project (soft delete)."""
        # Setup user and project
        email = f"archive-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Archive",
                "last_name": "Test",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        project_slug = f"archive-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Archive Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Archive the project
        archive_resp = await e2e_client.delete(
            f"/api/v1/projects/{project_id}",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert archive_resp.status_code == 200
        assert archive_resp.json()["success"] is True

        # Verify project is archived
        get_resp = await e2e_client.get(
            f"/api/v1/projects/{project_id}",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert get_resp.status_code == 200
        assert get_resp.json()["status"] == "archived"


class TestIssueWorkflows:
    """Test issue management workflows within projects."""

    async def test_create_and_list_issues(self, e2e_client):
        """Test creating and listing issues in a project."""
        # Setup user and project
        email = f"issue-test-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Issue",
                "last_name": "Tester",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        project_slug = f"issue-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Issue Test Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Create multiple issues
        issues = []
        for i in range(3):
            issue_resp = await e2e_client.post(
                f"/api/v1/projects/{project_id}/issues",
                headers={"Authorization": f"Bearer {tokens['access_token']}"},
                json={
                    "project_id": project_id,
                    "title": f"Test Issue {i + 1}",
                    "body": f"Description for issue {i + 1}",
                    "priority": ["low", "medium", "high"][i],
                },
            )
            assert issue_resp.status_code == 201, f"Failed: {issue_resp.text}"
            issues.append(issue_resp.json())

        # List issues
        list_resp = await e2e_client.get(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert list_resp.status_code == 200
        data = list_resp.json()
        assert data["pagination"]["total"] == 3

    async def test_issue_status_transitions(self, e2e_client):
        """Test issue status workflow transitions."""
        # Setup user and project
        email = f"status-test-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Status",
                "last_name": "Tester",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        project_slug = f"status-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Status Test Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Create issue
        issue_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={
                "project_id": project_id,
                "title": "Status Workflow Issue",
                "body": "Testing status transitions",
            },
        )
        issue = issue_resp.json()
        issue_id = issue["id"]
        assert issue["status"] == "open"

        # Transition through statuses
        for new_status in ["in_progress", "in_review", "closed"]:
            update_resp = await e2e_client.patch(
                f"/api/v1/projects/{project_id}/issues/{issue_id}",
                headers={"Authorization": f"Bearer {tokens['access_token']}"},
                json={"status": new_status},
            )
            assert update_resp.status_code == 200, f"Failed: {update_resp.text}"
            assert update_resp.json()["status"] == new_status

    async def test_issue_filtering(self, e2e_client):
        """Test issue filtering by status and priority."""
        # Setup user and project
        email = f"filter-test-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Filter",
                "last_name": "Tester",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        project_slug = f"filter-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Filter Test Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Create issues with different priorities
        for priority in ["low", "medium", "high"]:
            await e2e_client.post(
                f"/api/v1/projects/{project_id}/issues",
                headers={"Authorization": f"Bearer {tokens['access_token']}"},
                json={
                    "project_id": project_id,
                    "title": f"{priority.title()} Priority Issue",
                    "priority": priority,
                },
            )

        # Filter by high priority
        filter_resp = await e2e_client.get(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            params={"priority": "high"},
        )
        assert filter_resp.status_code == 200
        data = filter_resp.json()
        assert data["pagination"]["total"] == 1
        assert data["data"][0]["priority"] == "high"


class TestSprintWorkflows:
    """Test sprint planning and execution workflows."""

    async def test_sprint_lifecycle(self, e2e_client):
        """Test complete sprint lifecycle: plan -> start -> complete."""
        # Setup user and project
        email = f"sprint-test-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Sprint",
                "last_name": "Tester",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        project_slug = f"sprint-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Sprint Test Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Create sprint
        today = date.today()
        sprint_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/sprints",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={
                "project_id": project_id,
                "name": "Sprint 1",
                "number": 1,
                "goal": "Complete initial features",
                "start_date": today.isoformat(),
                "end_date": (today + timedelta(days=14)).isoformat(),
            },
        )
        assert sprint_resp.status_code == 201, f"Failed: {sprint_resp.text}"
        sprint = sprint_resp.json()
        sprint_id = sprint["id"]
        assert sprint["status"] == "planned"

        # Start sprint
        start_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/sprints/{sprint_id}/start",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert start_resp.status_code == 200, f"Failed: {start_resp.text}"
        assert start_resp.json()["status"] == "active"

        # Complete sprint
        complete_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/sprints/{sprint_id}/complete",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert complete_resp.status_code == 200, f"Failed: {complete_resp.text}"
        assert complete_resp.json()["status"] == "completed"

    async def test_add_issues_to_sprint(self, e2e_client):
        """Test adding issues to a sprint."""
        # Setup user and project
        email = f"sprint-issues-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "SprintIssues",
                "last_name": "Tester",
            },
        )
        login_resp = await e2e_client.post(
            "/api/v1/auth/login",
            json={"email": email, "password": password},
        )
        tokens = login_resp.json()

        project_slug = f"sprint-issues-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Sprint Issues Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Create sprint
        today = date.today()
        sprint_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/sprints",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={
                "project_id": project_id,
                "name": "Sprint 1",
                "number": 1,
                "start_date": today.isoformat(),
                "end_date": (today + timedelta(days=14)).isoformat(),
            },
        )
        assert sprint_resp.status_code == 201, f"Failed: {sprint_resp.text}"
        sprint = sprint_resp.json()
        sprint_id = sprint["id"]

        # Create issue
        issue_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={
                "project_id": project_id,
                "title": "Sprint Issue",
                "story_points": 5,
            },
        )
        issue = issue_resp.json()
        issue_id = issue["id"]

        # Add issue to sprint
        add_resp = await e2e_client.post(
            f"/api/v1/projects/{project_id}/sprints/{sprint_id}/issues",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            params={"issue_id": issue_id},
        )
        assert add_resp.status_code == 200, f"Failed: {add_resp.text}"

        # Verify issue is in sprint
        issue_check = await e2e_client.get(
            f"/api/v1/projects/{project_id}/issues/{issue_id}",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert issue_check.json()["sprint_id"] == sprint_id


class TestCrossEntityValidation:
    """Test validation across related entities."""

    async def test_cannot_access_other_users_project(self, e2e_client):
        """Test that users cannot access projects they don't own."""
        # Create two users
        owner_email = f"owner-{uuid4().hex[:8]}@example.com"
        other_email = f"other-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        # Register owner
        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": owner_email,
                "password": password,
                "first_name": "Owner",
                "last_name": "User",
            },
        )
        owner_tokens = (
            await e2e_client.post(
                "/api/v1/auth/login",
                json={"email": owner_email, "password": password},
            )
        ).json()

        # Register other user
        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": other_email,
                "password": password,
                "first_name": "Other",
                "last_name": "User",
            },
        )
        other_tokens = (
            await e2e_client.post(
                "/api/v1/auth/login",
                json={"email": other_email, "password": password},
            )
        ).json()

        # Owner creates project
        project_slug = f"private-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {owner_tokens['access_token']}"},
            json={"name": "Private Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Other user tries to access
        access_resp = await e2e_client.get(
            f"/api/v1/projects/{project_id}",
            headers={"Authorization": f"Bearer {other_tokens['access_token']}"},
        )
        assert access_resp.status_code == 403

    async def test_duplicate_project_slug_rejected(self, e2e_client):
        """Test that duplicate project slugs are rejected."""
        email = f"dup-test-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Dup",
                "last_name": "Tester",
            },
        )
        tokens = (
            await e2e_client.post(
                "/api/v1/auth/login",
                json={"email": email, "password": password},
            )
        ).json()

        slug = f"unique-slug-{uuid4().hex[:8]}"

        # First creation should succeed
        resp1 = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "First Project", "slug": slug},
        )
        assert resp1.status_code == 201

        # Second creation with same slug should fail
        resp2 = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Second Project", "slug": slug},
        )
        assert resp2.status_code == 409  # Conflict


class TestIssueStats:
    """Test issue statistics endpoints."""

    async def test_issue_stats_aggregation(self, e2e_client):
        """Test that issue stats are correctly aggregated."""
        email = f"stats-test-{uuid4().hex[:8]}@example.com"
        password = "SecurePass123!"

        await e2e_client.post(
            "/api/v1/auth/register",
            json={
                "email": email,
                "password": password,
                "first_name": "Stats",
                "last_name": "Tester",
            },
        )
        tokens = (
            await e2e_client.post(
                "/api/v1/auth/login",
                json={"email": email, "password": password},
            )
        ).json()

        project_slug = f"stats-project-{uuid4().hex[:8]}"
        create_resp = await e2e_client.post(
            "/api/v1/projects",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={"name": "Stats Project", "slug": project_slug},
        )
        project = create_resp.json()
        project_id = project["id"]

        # Create issues with different priorities and story points
        await e2e_client.post(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={
                "project_id": project_id,
                "title": "High Priority",
                "priority": "high",
                "story_points": 8,
            },
        )
        await e2e_client.post(
            f"/api/v1/projects/{project_id}/issues",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
            json={
                "project_id": project_id,
                "title": "Low Priority",
                "priority": "low",
                "story_points": 2,
            },
        )

        # Get stats
        stats_resp = await e2e_client.get(
            f"/api/v1/projects/{project_id}/issues/stats",
            headers={"Authorization": f"Bearer {tokens['access_token']}"},
        )
        assert stats_resp.status_code == 200
        stats = stats_resp.json()
        assert stats["total"] == 2
        assert stats["total_story_points"] == 10
