from unittest.mock import AsyncMock

import pytest

from dsg_core_client import DSGCoreClient
from dsg_core_client.schemas import BackgroundTaskStatus


@pytest.mark.asyncio
async def test_get_task_status_calls_bgtasks_endpoint() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        get_mock = AsyncMock(
            return_value={
                "jobId": "job-1",
                "ready": True,
                "success": True,
                "failed": False,
            }
        )
        setattr(client, "get", get_mock)

        response = await client.bgtasks.get_task_status("job-1")

        assert response == BackgroundTaskStatus(
            job_id="job-1", ready=True, success=True, failed=False
        )
        get_mock.assert_awaited_once_with(client.path("/bgtasks/job-1"))
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_wait_for_task_returns_when_ready_success() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        get_task_status_mock = AsyncMock(
            side_effect=[
                BackgroundTaskStatus(
                    job_id="job-2", ready=False, success=False, failed=False
                ),
                BackgroundTaskStatus(
                    job_id="job-2", ready=True, success=True, failed=False
                ),
            ]
        )
        setattr(client.bgtasks, "get_task_status", get_task_status_mock)

        response = await client.bgtasks.wait_for_task(
            "job-2", timeout_seconds=1.0, poll_interval_seconds=0.001
        )

        assert response.job_id == "job-2"
        assert response.ready is True
        assert response.success is True
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_wait_for_task_raises_for_failed_task() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        get_task_status_mock = AsyncMock(
            return_value=BackgroundTaskStatus(
                job_id="job-3", ready=True, success=False, failed=True
            )
        )
        setattr(client.bgtasks, "get_task_status", get_task_status_mock)

        with pytest.raises(RuntimeError, match="Background task job-3 failed"):
            await client.bgtasks.wait_for_task("job-3")
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_wait_for_task_raises_timeout() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        get_task_status_mock = AsyncMock(
            return_value=BackgroundTaskStatus(
                job_id="job-4", ready=False, success=False, failed=False
            )
        )
        setattr(client.bgtasks, "get_task_status", get_task_status_mock)

        with pytest.raises(TimeoutError, match="Timed out while waiting"):
            await client.bgtasks.wait_for_task(
                "job-4", timeout_seconds=0, poll_interval_seconds=0.001
            )
    finally:
        await client.close()


@pytest.mark.asyncio
async def test_wait_for_task_rejects_invalid_poll_interval() -> None:
    client = DSGCoreClient(base_url="https://example.org", token="token")
    try:
        with pytest.raises(
            ValueError, match="poll_interval_seconds must be greater than 0"
        ):
            await client.bgtasks.wait_for_task("job-5", poll_interval_seconds=0)
    finally:
        await client.close()
