from uuid import uuid4

import pytest

from domain.tasks.subtasks import SubTask, SubTaskStatus


def test_create_subtask_starts_waiting() -> None:
    # arrange
    task_id = uuid4()

    # act
    st = SubTask.create(task_id=task_id, inputs={"foo": "bar"})

    # assert
    assert st.task_id == task_id
    assert st.status is SubTaskStatus.WAITING
    assert st.inputs == {"foo": "bar"}
    assert st.outputs is None
    assert st.job_started is None
    assert st.job_completed is None


def test_start_transitions_to_in_progress_and_sets_cloud_logs_url() -> None:
    # arrange
    st = SubTask.create(task_id=uuid4())

    # act
    st.start(cloud_logs_url="https://example/log")

    # assert
    assert st.status is SubTaskStatus.IN_PROGRESS
    assert st.cloud_logs_url == "https://example/log"
    assert st.job_started is not None


def test_start_is_idempotent_from_in_progress() -> None:
    # arrange
    st = SubTask.create(task_id=uuid4())
    st.start()
    first_start = st.job_started

    # act
    st.start(cloud_logs_url="https://other")

    # assert
    assert st.status is SubTaskStatus.IN_PROGRESS
    assert st.job_started == first_start  # not overwritten
    assert st.cloud_logs_url == "https://other"


def test_start_rejects_from_terminal_status() -> None:
    # arrange
    st = SubTask.create(task_id=uuid4())
    st.complete()
    # act / assert
    with pytest.raises(ValueError):
        st.start()


def test_complete_marks_outputs_and_job_completed() -> None:
    # arrange
    st = SubTask.create(task_id=uuid4())
    st.start()

    # act
    st.complete({"uprn": "123"})

    # assert
    assert st.status is SubTaskStatus.COMPLETE
    assert st.outputs == {"result": {"uprn": "123"}}
    assert st.job_completed is not None


def test_complete_without_result_leaves_outputs_unset() -> None:
    # arrange
    st = SubTask.create(task_id=uuid4())
    # act
    st.complete()
    # assert
    assert st.outputs is None


def test_fail_records_error_in_outputs() -> None:
    # arrange
    st = SubTask.create(task_id=uuid4())
    err = RuntimeError("boom")

    # act
    st.fail(err)

    # assert
    assert st.status is SubTaskStatus.FAILED
    assert st.outputs == {"error": "boom"}
    assert st.job_completed is not None
