import asyncio
from typing import Any

import httpx
import pytest


async def poll_workflow_status(
    client: httpx.AsyncClient,
    execution_id: str,
    expected_status: str,
    timeout_seconds: int = 30,
) -> dict[str, Any]:
    for _ in range(timeout_seconds):
        await asyncio.sleep(1)
        status_response = await client.get(f"/v1/workflows/executions/{execution_id}")
        status_response.raise_for_status()
        status_data = status_response.json()
        status = status_data.get("status")

        if status == expected_status:
            return status_data
        elif status in ["FAILED", "TERMINATED", "TIMED_OUT", "COMPLETED"]:
            if status != expected_status:
                raise RuntimeError(f"Workflow ended with status: {status}, expected: {expected_status}")

    raise TimeoutError(f"Workflow did not reach {expected_status} status within {timeout_seconds}s")


async def execute_workflow_and_wait(
    client: httpx.AsyncClient,
    workflow_name: str,
    input_data: dict[str, Any],
    timeout_seconds: int = 30,
) -> dict[str, Any]:
    response = await client.post(
        f"/v1/workflows/{workflow_name}/execute",
        json={"input": input_data},
    )
    response.raise_for_status()
    data = response.json()

    execution_id = data.get("execution_id")
    if not execution_id:
        raise ValueError(f"No execution_id returned: {data}")

    for _ in range(timeout_seconds):
        await asyncio.sleep(1)

        status_response = await client.get(f"/v1/workflows/executions/{execution_id}")
        status_response.raise_for_status()
        status_data = status_response.json()

        status = status_data.get("status")
        if status == "COMPLETED":
            return status_data
        elif status in ["FAILED", "TERMINATED", "TIMED_OUT"]:
            raise RuntimeError(f"Workflow {workflow_name} ended with status: {status}")

    raise TimeoutError(f"Workflow {workflow_name} did not complete within {timeout_seconds}s")


@pytest.mark.integration
@pytest.mark.asyncio
async def test_hello_world_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "example-hello-world-workflow",
            {"document_title": "test-document"},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_chain_executor_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "chain-executor-example",
            {},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_list_executor_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "list-executor-example",
            {},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_offset_pagination_executor_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "offset-pagination-executor-example",
            {},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
@pytest.mark.skip
async def test_continue_as_new_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "example-continue-as-new",
            {"offset": 500, "limit": 100, "total_processed": 0},  # start at offset 500 to complete immediately
            timeout_seconds=60,  # Increased timeout
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.skip
@pytest.mark.integration
@pytest.mark.asyncio
async def test_finance_agent_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "finance_agent_workflow",
            {"question": "What was the ECB interest rate in 2023?"},
            timeout_seconds=180,  # Agent workflows may take longer
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_sub_workflow_execution(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "example-with-sub-workflow",
            {"document_title": "test-sub-workflow"},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_scheduled_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "example-with-schedule",
            {"document_title": "test-scheduled-workflow"},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_rate_limited_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "rate-limited-workflow",
            {"n_turns": 3, "rate_limit_number": 2},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_local_activities_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "local-activity-demo",
            {"email": "test@example.com", "name": "Test User"},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_different_task_queue_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "example-different-task-queue-workflow",
            {"document_title": "test-task-queue"},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_riddle_game_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        response = await api_client.post(
            "/v1/workflows/example-interactive-game-workflow/execute",
            json={"input": {"initial_player_name": "TestPlayer", "max_riddles": 2}},
        )
        response.raise_for_status()
        data = response.json()
        execution_id = data.get("execution_id")
        if not execution_id:
            raise ValueError(f"No execution_id returned: {data}")

        # Give workflow time to initialize
        await asyncio.sleep(2)
        signal_response = await api_client.post(
            f"/v1/workflows/executions/{execution_id}/signals",
            json={"name": "submit_answer", "input": {"answer": "map"}},
        )
        signal_response.raise_for_status()
        await asyncio.sleep(2)
        signal_response = await api_client.post(
            f"/v1/workflows/executions/{execution_id}/signals",
            json={"name": "submit_answer", "input": {"answer": "needle"}},
        )
        signal_response.raise_for_status()

        result = await poll_workflow_status(api_client, execution_id, "COMPLETED", timeout_seconds=30)
        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_assist_hello_world_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "assist-workflow-hello-world",
            {"document_title": "test-assist-document"},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_long_hello_world_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "example-long-hello-world-workflow",
            {"document_title": "test-long-document"},
            timeout_seconds=60,
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_dependency_injection_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "example-dependency-injection-workflow",
            {"user": "test-user"},
            timeout_seconds=60,
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_worker_versioning_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        result = await execute_workflow_and_wait(
            api_client,
            "WorkerVersioningExample",
            {"message": "test-versioning"},
        )

        assert result["status"] == "COMPLETED"


@pytest.mark.integration
@pytest.mark.asyncio
async def test_failing_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        response = await api_client.post(
            "/v1/workflows/example-failing-workflow/execute",
            json={"input": {"document_title": "test-document"}},
        )
        response.raise_for_status()
        data = response.json()
        execution_id = data.get("execution_id")
        if not execution_id:
            raise ValueError(f"No execution_id returned: {data}")

        result = await poll_workflow_status(api_client, execution_id, "FAILED", timeout_seconds=30)
        assert result["status"] == "FAILED"


@pytest.mark.skip
@pytest.mark.integration
@pytest.mark.asyncio
async def test_failing_tool_call_workflow(api_client: httpx.AsyncClient) -> None:
    async with api_client:
        response = await api_client.post(
            "/v1/workflows/failing-tool-call-workflow/execute",
            json={"input": {}},
        )
        response.raise_for_status()
        data = response.json()
        execution_id = data.get("execution_id")
        if not execution_id:
            raise ValueError(f"No execution_id returned: {data}")

        result = await poll_workflow_status(api_client, execution_id, "COMPLETED", timeout_seconds=30)
        assert result["status"] == "COMPLETED"


# Note: The following workflows are excluded from integration tests because they:
# - Require interactive user input (multi_turn_chat_workflow)
# - Require document attachments/URLs (insurance_claims_workflow)
# - Are streaming workflows that don't follow request/response pattern
#   (travel_agent_streaming_workflow, local_session_streaming_workflow,
#    streaming-tokens-example, streaming-tokens-with-progress-example,
#    streaming-with-retry-example)
# - Use external MCP servers that may not be available in test environment
#   (mcp_sse_workflow, mcp_tools_workflow, web-search-workflow)
# - Use updates and run indefinitely (simple-chatbot-workflow)
#
