# SPDX-License-Identifier: Apache-2.0
"""Integration tests for the Python HPI SDK — requires a running HPI server."""

import os
import pytest

from hpi_client import HPIClient
from hpi_client.client import HPIError

BASE_URL = os.environ.get("HPI_TEST_URL", "http://localhost:5188")
TOKEN = os.environ.get("HPI_TEST_TOKEN", "")


@pytest.fixture(scope="module")
def client():
    if not TOKEN:
        pytest.skip("Set HPI_TEST_TOKEN env var to run integration tests")
    with HPIClient(BASE_URL, TOKEN) as c:
        yield c


# ── Tasks ────────────────────────────────────────────────────────


class TestTaskLifecycle:
    """Create → get → complete → verify."""

    task_id: str = ""

    def test_create_task(self, client: HPIClient):
        task = client.create_task(
            title="Python SDK Integration Test",
            steps=[
                {
                    "id": "step1",
                    "title": "Answer",
                    "blocks": [
                        {"type": "mdsvex", "content": "Hello from the **Python SDK** test."},
                        {"type": "input", "field": {"name": "answer", "label": "Your answer", "kind": "text"}},
                    ],
                }
            ],
            metadata={"source": "python-sdk-test"},
        )

        assert task["task_id"]
        assert task["created_at"]
        TestTaskLifecycle.task_id = task["task_id"]

    def test_get_task(self, client: HPIClient):
        task = client.get_task(TestTaskLifecycle.task_id)

        assert task["task_id"] == TestTaskLifecycle.task_id
        assert task["status"] == "pending"
        assert task["title"] == "Python SDK Integration Test"

    def test_get_task_with_definition(self, client: HPIClient):
        task = client.get_task(TestTaskLifecycle.task_id, include_definition=True)

        assert task["steps"] is not None
        assert len(task["steps"]) == 1
        assert task["steps"][0]["id"] == "step1"

    def test_complete_task(self, client: HPIClient):
        result = client.complete_task(
            TestTaskLifecycle.task_id,
            data={"answer": "Hello from Python SDK"},
        )

        assert result["task_id"] == TestTaskLifecycle.task_id
        assert result["status"] == "completed"

    def test_verify_completion_data(self, client: HPIClient):
        task = client.get_task(TestTaskLifecycle.task_id)

        assert task["status"] == "completed"
        assert task["data"] == {"answer": "Hello from Python SDK"}


class TestTaskCancel:
    """Create → cancel → verify."""

    task_id: str = ""

    def test_create_and_cancel(self, client: HPIClient):
        task = client.create_task(
            title="Task to Cancel (Python)",
            steps=[{"id": "s1", "title": "Step", "blocks": [{"type": "input", "field": {"name": "x", "label": "X", "kind": "text"}}]}],
        )
        TestTaskCancel.task_id = task["task_id"]

        result = client.cancel_task(TestTaskCancel.task_id, reason="Testing cancellation")
        assert result["status"] == "cancelled"

    def test_verify_cancelled(self, client: HPIClient):
        task = client.get_task(TestTaskCancel.task_id)
        assert task["status"] == "cancelled"


class TestListTasks:
    def test_list_tasks(self, client: HPIClient):
        result = client.list_tasks(limit=5)

        assert "tasks" in result
        assert len(result["tasks"]) > 0
        assert result["total"] > 0

    def test_list_tasks_with_filters(self, client: HPIClient):
        result = client.list_tasks(status="completed", sort="newest", limit=3)

        assert "tasks" in result
        for task in result["tasks"]:
            assert task["status"] == "completed"

    def test_list_task_templates(self, client: HPIClient):
        result = client.list_task_templates()
        assert "template_ids" in result


# ── Task Links ───────────────────────────────────────────────────


class TestTaskLinks:
    task_id: str = ""
    link_id: str = ""

    def test_create_task_and_link(self, client: HPIClient):
        task = client.create_task(
            title="Task with Links (Python)",
            steps=[{"id": "s1", "title": "Step", "blocks": [{"type": "input", "field": {"name": "x", "label": "X", "kind": "text"}}]}],
        )
        TestTaskLinks.task_id = task["task_id"]

        link = client.create_task_link(
            TestTaskLinks.task_id,
            assignee_email="test@example.com",
            require_otp=False,
        )

        assert link["link_id"]
        assert link["url"]
        TestTaskLinks.link_id = link["link_id"]

    def test_list_task_links(self, client: HPIClient):
        result = client.list_task_links(TestTaskLinks.task_id)
        assert len(result["links"]) >= 1

    def test_delete_task_link(self, client: HPIClient):
        result = client.delete_task_link(TestTaskLinks.task_id, TestTaskLinks.link_id)
        assert result["deleted"] is True


# ── Wait for Task ────────────────────────────────────────────────


class TestWaitForTask:
    def test_wait_returns_immediately_for_completed(self, client: HPIClient):
        # Create and complete a task
        task = client.create_task(
            title="Wait Test (Python)",
            steps=[{"id": "s1", "title": "Step", "blocks": [{"type": "input", "field": {"name": "x", "label": "X", "kind": "text"}}]}],
        )
        client.complete_task(task["task_id"], data={"x": "done"})

        # Wait should return immediately
        result = client.wait_for_task(task["task_id"], timeout=5)
        assert result["status"] == "completed"
        assert result["data"] == {"x": "done"}


# ── Error Handling ───────────────────────────────────────────────


class TestErrors:
    def test_404_raises_hpi_error(self, client: HPIClient):
        with pytest.raises(HPIError) as exc_info:
            client.get_task("nonexistent-task-id")
        assert exc_info.value.status == 404

    def test_409_on_double_complete(self, client: HPIClient):
        task = client.create_task(
            title="Double Complete Test",
            steps=[{"id": "s1", "title": "Step", "blocks": [{"type": "input", "field": {"name": "x", "label": "X", "kind": "text"}}]}],
        )
        client.complete_task(task["task_id"], data={"x": "first"})

        with pytest.raises(HPIError) as exc_info:
            client.complete_task(task["task_id"], data={"x": "second"})
        assert exc_info.value.status == 409

    def test_409_on_cancel_completed(self, client: HPIClient):
        task = client.create_task(
            title="Cancel Completed Test",
            steps=[{"id": "s1", "title": "Step", "blocks": [{"type": "input", "field": {"name": "x", "label": "X", "kind": "text"}}]}],
        )
        client.complete_task(task["task_id"])

        with pytest.raises(HPIError) as exc_info:
            client.cancel_task(task["task_id"])
        assert exc_info.value.status == 409


# ── File Upload ──────────────────────────────────────────────────


class TestFileUpload:
    def test_upload_file(self, client: HPIClient):
        try:
            result = client.upload_file(
                b"Hello from Python SDK test",
                "test.txt",
                "text/plain",
            )
            assert result["name"] == "test.txt"
            assert result["size"] > 0
            assert result["type"] == "text/plain"
        except HPIError as e:
            if e.status in (500, 503):
                pytest.skip("S3 not configured")
            raise
