"""Enqueue helper — submit a job to the arq queue from the request cycle.

A short-lived pool per call keeps things simple (enqueues are rare, admin-driven
actions). Redis being down degrades to a clean 503 rather than a crash
(graceful degradation)."""

import uuid
from typing import Any

from arq import create_pool
from arq.connections import RedisSettings

from app.core.config import get_settings
from app.core.logging import get_logger
from app.domain.errors import DependencyUnavailableError

log = get_logger("worker.queue")


async def enqueue(function: str, **kwargs: Any) -> str:
    """Enqueue ``function`` by name, returning the job id. Raises
    :class:`DependencyUnavailableError` if the queue can't be reached."""
    settings = get_settings()
    try:
        pool = await create_pool(RedisSettings.from_dsn(str(settings.redis_url)))
    except Exception as exc:
        raise DependencyUnavailableError("Task queue (Redis) is unavailable.") from exc
    try:
        job = await pool.enqueue_job(function, **kwargs)
    finally:
        await pool.aclose()
    if job is None:
        raise DependencyUnavailableError("Could not enqueue job.")
    return str(job.job_id)


async def enqueue_enrich(track_id: uuid.UUID) -> None:
    """Best-effort enqueue of metadata enrichment for a freshly stored track.

    The track is already persisted, so enrichment is a follow-up, not a barrier:
    if the queue is unreachable we log and move on (graceful degradation). The
    track stays ``metadata_status=pending`` and can be re-enriched later.

    Deferred a few seconds so the caller's DB transaction is committed before the
    worker looks the track up (the upload request commits only after it returns)."""
    try:
        await enqueue("enrich_track", track_id=str(track_id), _defer_by=5)
    except DependencyUnavailableError:
        log.warning("enrich_enqueue_failed", track_id=str(track_id))
