"""arq task: enrich one track's metadata (plan §6.2, §1D).

Wires the §6.2 pipeline adapters to :class:`MetadataEnrichmentService` and runs
it in the worker's own transactional session. Enqueued (deferred) after upload
and after a local-folder import. Idempotent and best-effort — a missing track or
a ``manual`` one is a clean no-op.
"""

import uuid
from typing import Any

from app.application.metadata_service import MetadataEnrichmentService
from app.core.config import get_settings
from app.core.logging import get_logger
from app.infrastructure.db import session_scope
from app.infrastructure.db.repositories import (
    SqlAlchemyAlbumRepository,
    SqlAlchemyArtistRepository,
    SqlAlchemyTrackRepository,
)
from app.infrastructure.metadata.acoustid import AcoustIdHttpClient
from app.infrastructure.metadata.cover_extractor import MutagenCoverExtractor
from app.infrastructure.metadata.coverart import CoverArtArchiveClient
from app.infrastructure.metadata.fingerprint import FpcalcFingerprinter
from app.infrastructure.metadata.tags import MutagenTagReader
from app.infrastructure.storage.provider import get_file_storage

log = get_logger("worker.enrich")


async def enrich_track(_ctx: dict[str, Any], *, track_id: str) -> dict[str, Any]:
    settings = get_settings()
    api_key = settings.acoustid_api_key.get_secret_value() if settings.acoustid_api_key else None
    acoustid = AcoustIdHttpClient(
        api_key=api_key,
        user_agent=settings.musicbrainz_user_agent,
        api_url=settings.acoustid_api_url,
    )
    cover_provider = CoverArtArchiveClient(
        user_agent=settings.musicbrainz_user_agent,
        enabled=settings.coverart_enabled,
        base_url=settings.coverart_base_url,
    )

    tid = uuid.UUID(track_id)
    try:
        async with session_scope() as session:
            service = MetadataEnrichmentService(
                tracks=SqlAlchemyTrackRepository(session),
                artists=SqlAlchemyArtistRepository(session),
                albums=SqlAlchemyAlbumRepository(session),
                storage=get_file_storage(),
                tag_reader=MutagenTagReader(),
                fingerprinter=FpcalcFingerprinter(settings.fpcalc_path),
                acoustid=acoustid,
                cover_extractor=MutagenCoverExtractor(),
                cover_provider=cover_provider,
                acoustid_trust_score=settings.acoustid_trust_score,
            )
            result = await service.enrich(tid)
    except Exception as exc:
        # The run's own transaction rolled back, leaving the track stuck at
        # ``pending``. Record the failure in a fresh session so the UI shows a
        # ``failed`` status with a reason instead of a silent, endless spinner.
        log.exception("enrich_failed", track_id=track_id)
        async with session_scope() as session:
            await SqlAlchemyTrackRepository(session).mark_enrichment_failed(
                tid, error=f"Enrichment crashed: {type(exc).__name__}: {exc}"
            )
        return {"track_id": track_id, "status": "failed", "mbid": None}

    return {
        "track_id": str(result.track_id),
        "status": result.status,
        "mbid": result.matched_mbid,
    }
