"""Job polling resource for async batch TTS jobs."""

from __future__ import annotations

import asyncio
import time
from typing import TYPE_CHECKING, Any

from murmr._errors import MurmrError
from murmr._types import JobStatus
from murmr._validate import validate_id

if TYPE_CHECKING:
    from collections.abc import Callable

    from murmr._client import AsyncMurmrClient, MurmrClient

MIN_POLL_INTERVAL = 1.0


class AsyncJobs:
    """Async resource for managing batch TTS jobs."""

    def __init__(self, client: AsyncMurmrClient) -> None:
        self._client = client

    async def get(self, job_id: str) -> JobStatus:
        """Get the current status of a batch job."""
        validate_id(job_id, "jobId")
        response = await self._client.request("GET", f"/v1/jobs/{job_id}")
        data: dict[str, Any] = response.json()
        return JobStatus.model_validate(data)

    async def wait_for_completion(
        self,
        job_id: str,
        *,
        poll_interval_s: float = 3.0,
        timeout_s: float = 900.0,
        on_poll: Callable[[JobStatus], None] | None = None,
    ) -> JobStatus:
        """Poll until the job completes or fails.

        Args:
            job_id: The job ID to poll.
            poll_interval_s: Seconds between polls (minimum 1.0).
            timeout_s: Maximum seconds to wait before raising.
            on_poll: Optional callback invoked after each poll.

        Returns:
            JobStatus with status 'completed'.

        Raises:
            MurmrError: If the job fails or polling times out.
        """
        validate_id(job_id, "jobId")
        interval = max(poll_interval_s, MIN_POLL_INTERVAL)
        deadline = time.monotonic() + timeout_s

        while time.monotonic() < deadline:
            status = await self.get(job_id)
            if on_poll is not None:
                on_poll(status)

            if status.status == "completed":
                return status
            if status.status == "failed":
                raise MurmrError(
                    status.error or "Job failed",
                    code="JOB_FAILED",
                )

            await asyncio.sleep(interval)

        raise MurmrError("Job polling timed out", code="TIMEOUT")


class SyncJobs:
    """Sync resource for managing batch TTS jobs."""

    def __init__(self, client: MurmrClient) -> None:
        self._client = client

    def get(self, job_id: str) -> JobStatus:
        """Get the current status of a batch job."""
        validate_id(job_id, "jobId")
        response = self._client.request("GET", f"/v1/jobs/{job_id}")
        data: dict[str, Any] = response.json()
        return JobStatus.model_validate(data)

    def wait_for_completion(
        self,
        job_id: str,
        *,
        poll_interval_s: float = 3.0,
        timeout_s: float = 900.0,
        on_poll: Callable[[JobStatus], None] | None = None,
    ) -> JobStatus:
        """Poll until the job completes or fails."""
        validate_id(job_id, "jobId")
        interval = max(poll_interval_s, MIN_POLL_INTERVAL)
        deadline = time.monotonic() + timeout_s

        while time.monotonic() < deadline:
            status = self.get(job_id)
            if on_poll is not None:
                on_poll(status)

            if status.status == "completed":
                return status
            if status.status == "failed":
                raise MurmrError(
                    status.error or "Job failed",
                    code="JOB_FAILED",
                )

            time.sleep(interval)

        raise MurmrError("Job polling timed out", code="TIMEOUT")
