"""Tests for tasks router (/api/recipes/{id}/tasks, /api/tasks, /api/subtasks)."""
import pytest
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession

from src.backend.models.orm.user import User
from src.backend.tests.conftest import auth_headers, create_test_recipe


class TestListTasks:
    """GET /api/recipes/{recipe_id}/tasks tests."""

    async def test_list_tasks(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Authenticated user can list tasks for a recipe."""
        recipe = await create_test_recipe(db_session, maker_user.id)
        resp = await client.get(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
        )
        assert resp.status_code == 200
        data = resp.json()
        assert isinstance(data, list)
        assert len(data) >= 1
        assert data[0]["title"] == "Test Task"
        assert len(data[0]["subtasks"]) >= 1


class TestCreateTask:
    """POST /api/recipes/{recipe_id}/tasks tests."""

    async def test_create_task(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Maker can add a task (triggers copy-on-write new version)."""
        recipe = await create_test_recipe(db_session, maker_user.id)
        resp = await client.post(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
            json={
                "title": "New Task",
                "directive": "Inspect surface",
                "subtasks": [
                    {
                        "marker_number": 1,
                        "description": "Surface roughness",
                        "nominal": 5.0,
                        "utl": 5.5,
                        "ltl": 4.5,
                        "unit": "um",
                    }
                ],
            },
        )
        assert resp.status_code == 201
        data = resp.json()
        assert data["title"] == "New Task"
        assert len(data["subtasks"]) == 1
        assert data["subtasks"][0]["description"] == "Surface roughness"


class TestUpdateTask:
    """PUT /api/tasks/{task_id} tests."""

    async def test_update_task(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Maker can update a task on the current version."""
        recipe = await create_test_recipe(db_session, maker_user.id)
        # Get task list to find the task ID
        tasks_resp = await client.get(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
        )
        task_id = tasks_resp.json()[0]["id"]

        resp = await client.put(
            f"/api/tasks/{task_id}",
            headers=auth_headers(maker_user),
            json={"title": "Updated Task Title"},
        )
        assert resp.status_code == 200
        assert resp.json()["title"] == "Updated Task Title"


class TestDeleteTask:
    """DELETE /api/tasks/{task_id} tests."""

    async def test_delete_task(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Maker can delete a task from the current version."""
        recipe = await create_test_recipe(db_session, maker_user.id)
        tasks_resp = await client.get(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
        )
        task_id = tasks_resp.json()[0]["id"]

        resp = await client.delete(
            f"/api/tasks/{task_id}", headers=auth_headers(maker_user)
        )
        assert resp.status_code == 204


class TestCreateSubtask:
    """POST /api/tasks/{task_id}/subtasks tests."""

    async def test_create_subtask(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Maker can add a subtask to a task."""
        recipe = await create_test_recipe(db_session, maker_user.id)
        tasks_resp = await client.get(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
        )
        task_id = tasks_resp.json()[0]["id"]

        resp = await client.post(
            f"/api/tasks/{task_id}/subtasks",
            headers=auth_headers(maker_user),
            json={
                "marker_number": 2,
                "description": "Width measurement",
                "nominal": 20.0,
                "utl": 20.5,
                "ltl": 19.5,
                "unit": "mm",
            },
        )
        assert resp.status_code == 201
        data = resp.json()
        assert data["marker_number"] == 2
        assert data["description"] == "Width measurement"


class TestUpdateSubtask:
    """PUT /api/subtasks/{subtask_id} tests."""

    async def test_update_subtask(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Maker can update a subtask."""
        recipe = await create_test_recipe(db_session, maker_user.id)
        tasks_resp = await client.get(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
        )
        subtask_id = tasks_resp.json()[0]["subtasks"][0]["id"]

        resp = await client.put(
            f"/api/subtasks/{subtask_id}",
            headers=auth_headers(maker_user),
            json={"description": "Updated description", "nominal": 12.0},
        )
        assert resp.status_code == 200
        assert resp.json()["description"] == "Updated description"


class TestReorderTasks:
    """PUT /api/tasks/reorder tests."""

    async def test_reorder_tasks(
        self,
        client: AsyncClient,
        maker_user: User,
        db_session: AsyncSession,
    ):
        """Maker can reorder tasks by providing task IDs in desired order."""
        recipe = await create_test_recipe(db_session, maker_user.id)

        # Add a second task (no measurements → appended to current version)
        add_resp = await client.post(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
            json={"title": "Second Task", "subtasks": []},
        )
        assert add_resp.status_code == 201

        # Force SQLA to re-fetch RecipeVersion.tasks: the shared test session
        # caches the collection from create_test_recipe, so the GET below would
        # otherwise return a stale list. In prod each request gets its own session.
        db_session.expunge_all()

        tasks_resp = await client.get(
            f"/api/recipes/{recipe.id}/tasks",
            headers=auth_headers(maker_user),
        )
        tasks = tasks_resp.json()
        assert len(tasks) >= 2

        task_ids = [t["id"] for t in tasks]
        # Reverse the order
        reversed_ids = list(reversed(task_ids))

        resp = await client.put(
            "/api/tasks/reorder",
            headers=auth_headers(maker_user),
            json={"task_ids": reversed_ids},
        )
        assert resp.status_code == 200
        reordered = resp.json()
        assert [t["id"] for t in reordered] == reversed_ids
