"""Tasks plugin tests — CRUD, assign, status update, filtering."""

from __future__ import annotations

import pytest
from httpx import AsyncClient

from tests.conftest import ORIGIN_HEADER, login_client, seed_tenant_and_users


@pytest.mark.asyncio
class TestTaskList:
    """GET /api/v1/tasks"""

    async def test_list_tasks_returns_200(self, client: AsyncClient, db_session):
        """GET /tasks returns 200 with paginated list."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.get("/api/v1/tasks", headers=ORIGIN_HEADER)
        assert resp.status_code == 200
        data = resp.json()
        assert "items" in data
        assert "total" in data
        assert "page" in data
        assert "page_size" in data

    async def test_list_tasks_with_status_filter(self, client: AsyncClient, db_session):
        """GET /tasks?status=open filters by status."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.get("/api/v1/tasks?status=open", headers=ORIGIN_HEADER)
        assert resp.status_code == 200
        for item in resp.json()["items"]:
            assert item["status"] == "open"

    async def test_list_tasks_requires_auth(self, client: AsyncClient, db_session):
        """GET /tasks without auth returns 401."""
        resp = await client.get("/api/v1/tasks", headers=ORIGIN_HEADER)
        assert resp.status_code == 401


@pytest.mark.asyncio
class TestTaskCreate:
    """POST /api/v1/tasks"""

    async def test_create_task_returns_201(self, client: AsyncClient, db_session):
        """POST /tasks creates a task and returns 201."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.post(
            "/api/v1/tasks",
            json={"title": "Call customer", "priority": "high"},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 201
        data = resp.json()
        assert data["title"] == "Call customer"
        assert data["priority"] == "high"
        assert data["status"] == "open"

    async def test_create_task_with_due_date(self, client: AsyncClient, db_session):
        """POST /tasks with due_date stores it correctly."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.post(
            "/api/v1/tasks",
            json={"title": "Follow up", "due_date": "2025-12-31T10:00:00Z"},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 201
        assert resp.json()["due_date"] is not None

    async def test_create_task_empty_title_returns_422(self, client: AsyncClient, db_session):
        """POST /tasks with empty title returns 422."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.post(
            "/api/v1/tasks",
            json={"title": ""},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 422


@pytest.mark.asyncio
class TestTaskUpdate:
    """PATCH /api/v1/tasks/{id}"""

    async def test_update_task_returns_200(self, client: AsyncClient, db_session):
        """PATCH /tasks/{id} updates the task."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        # Create
        create_resp = await client.post(
            "/api/v1/tasks",
            json={"title": "Original"},
            headers=ORIGIN_HEADER,
        )
        task_id = create_resp.json()["id"]
        # Update
        resp = await client.patch(
            f"/api/v1/tasks/{task_id}",
            json={"title": "Updated", "status": "in_progress"},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 200
        assert resp.json()["title"] == "Updated"
        assert resp.json()["status"] == "in_progress"

    async def test_update_task_not_found_returns_404(self, client: AsyncClient, db_session):
        """PATCH non-existent task returns 404."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        resp = await client.patch(
            "/api/v1/tasks/00000000-0000-0000-0000-000000000000",
            json={"title": "Updated"},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 404


@pytest.mark.asyncio
class TestTaskStatus:
    """POST /api/v1/tasks/{id}/status"""

    async def test_update_status_returns_200(self, client: AsyncClient, db_session):
        """POST /tasks/{id}/status updates status."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        create_resp = await client.post(
            "/api/v1/tasks",
            json={"title": "Task to complete"},
            headers=ORIGIN_HEADER,
        )
        task_id = create_resp.json()["id"]
        resp = await client.post(
            f"/api/v1/tasks/{task_id}/status",
            json={"status": "done"},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 200
        assert resp.json()["status"] == "done"

    async def test_update_status_invalid_returns_422(self, client: AsyncClient, db_session):
        """POST /tasks/{id}/status with invalid status returns 422."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        create_resp = await client.post(
            "/api/v1/tasks",
            json={"title": "Task"},
            headers=ORIGIN_HEADER,
        )
        task_id = create_resp.json()["id"]
        resp = await client.post(
            f"/api/v1/tasks/{task_id}/status",
            json={"status": "invalid"},
            headers=ORIGIN_HEADER,
        )
        assert resp.status_code == 422


@pytest.mark.asyncio
class TestTaskDelete:
    """DELETE /api/v1/tasks/{id}"""

    async def test_delete_task_returns_204(self, client: AsyncClient, db_session):
        """DELETE /tasks/{id} soft-deletes the task."""
        await seed_tenant_and_users(db_session)
        await login_client(client, "admin@tenanta.com")
        create_resp = await client.post(
            "/api/v1/tasks",
            json={"title": "To delete"},
            headers=ORIGIN_HEADER,
        )
        task_id = create_resp.json()["id"]
        resp = await client.delete(f"/api/v1/tasks/{task_id}", headers=ORIGIN_HEADER)
        assert resp.status_code == 204
        # Verify it's gone from list
        list_resp = await client.get("/api/v1/tasks", headers=ORIGIN_HEADER)
        assert not any(t["id"] == task_id for t in list_resp.json()["items"])
