import pytest
from httpx import Response

from prefect_hex.exceptions import TERMINAL_STATUS_EXCEPTIONS, HexProjectRunTimedOut
from prefect_hex.models.project import ProjectStatusResponsePayload
from prefect_hex.project import trigger_project_run_and_wait_for_completion


@pytest.fixture()
def project_run_json():
    return {
        "projectId": "123",
        "runId": "1234",
        "runUrl": "https://app.hex.tech/12345/app/123",
        "runStatusUrl": "https://app.hex.tech/api/v1/project/12345/run/1234",
        "traceId": "123456",
    }


@pytest.fixture()
def project_status_json():
    return {
        "projectId": "123",
        "runId": "1234",
        "status": "COMPLETED",
        "runUrl": "https://app.hex.tech/12345/app/123",
        "startTime": "2022-11-15T23:53:31.554Z",
        "endTime": None,
        "elapsedTime": 1234,
        "traceId": "123456",
    }


async def test_trigger_project_run_and_wait_for_completion(
    hex_credentials, respx_mock, project_run_json, project_status_json
):
    respx_mock.post("https://app.hex.tech/api/v1/project/123/run").mock(
        return_value=Response(200, json=project_run_json)
    )
    respx_mock.get("https://app.hex.tech/api/v1/project/123/run/1234").mock(
        return_value=Response(200, json=project_status_json)
    )
    actual = await trigger_project_run_and_wait_for_completion(
        project_id="123", hex_credentials=hex_credentials
    )
    assert isinstance(actual, ProjectStatusResponsePayload)
    assert actual.project_id == "123"
    assert actual.run_id == "1234"


@pytest.mark.parametrize("status", ["RUNNING", "PENDING"])
async def test_trigger_sync_run_and_wait_for_completion_timeout(
    hex_credentials, respx_mock, project_run_json, project_status_json, status
):
    project_status_json["status"] = status
    respx_mock.post("https://app.hex.tech/api/v1/project/123/run").mock(
        return_value=Response(200, json=project_run_json)
    )
    respx_mock.get("https://app.hex.tech/api/v1/project/123/run/1234").mock(
        return_value=Response(200, json=project_status_json)
    )
    with pytest.raises(HexProjectRunTimedOut, match="Max wait time of 2 seconds"):
        await trigger_project_run_and_wait_for_completion(
            project_id="123",
            hex_credentials=hex_credentials,
            max_wait_seconds=2,
            poll_frequency_seconds=1,
        )


@pytest.mark.parametrize("status", TERMINAL_STATUS_EXCEPTIONS.keys())
async def test_trigger_project_run_and_wait_for_completion_unsuccessful(
    hex_credentials, respx_mock, project_run_json, project_status_json, status
):
    if status.value == "COMPLETED":
        pytest.skip()

    project_status_json["status"] = status.value
    respx_mock.post("https://app.hex.tech/api/v1/project/123/run").mock(
        return_value=Response(200, json=project_run_json)
    )
    respx_mock.get("https://app.hex.tech/api/v1/project/123/run/1234").mock(
        return_value=Response(200, json=project_status_json)
    )
    with pytest.raises(
        TERMINAL_STATUS_EXCEPTIONS[status],
        match=f"was unsuccessful with {status.value!r}",
    ):
        await trigger_project_run_and_wait_for_completion(
            project_id="123",
            hex_credentials=hex_credentials,
        )
