from __future__ import annotations

import asyncio
import logging

from api.v1.schemas.weekly_exploration import (
    WeeklyExplorationSection,
    WeeklyExplorationTrack,
)
from infrastructure.cover_urls import release_cover_url, release_group_cover_url
from repositories.protocols import (
    ListenBrainzRepositoryProtocol,
    MusicBrainzRepositoryProtocol,
)

logger = logging.getLogger(__name__)


class WeeklyExplorationService:
    def __init__(
        self,
        listenbrainz_repo: ListenBrainzRepositoryProtocol,
        musicbrainz_repo: MusicBrainzRepositoryProtocol,
    ) -> None:
        self._lb_repo = listenbrainz_repo
        self._mb_repo = musicbrainz_repo

    async def build_section(self, username: str) -> WeeklyExplorationSection | None:
        try:
            playlists = await self._lb_repo.get_recommendation_playlists(username)
            if not playlists:
                return None

            newest = next(
                (p for p in playlists if p.get("source_patch") == "weekly-exploration"),
                playlists[0],
            )
            playlist_id = newest.get("playlist_id", "")
            if not playlist_id:
                return None

            playlist = await self._lb_repo.get_playlist_tracks(playlist_id)
            if not playlist or not playlist.tracks:
                return None

            unique_release_ids = list({
                track.caa_release_mbid for track in playlist.tracks if track.caa_release_mbid
            })
            rg_results = await asyncio.gather(
                *(
                    self._mb_repo.get_release_group_id_from_release(release_id)
                    for release_id in unique_release_ids
                ),
                return_exceptions=True,
            )
            release_to_rg = {
                release_id: release_group_id
                for release_id, release_group_id in zip(unique_release_ids, rg_results)
                if isinstance(release_group_id, str) and release_group_id
            }

            tracks: list[WeeklyExplorationTrack] = []
            for track in playlist.tracks:
                artist_mbid = track.artist_mbids[0] if track.artist_mbids else None
                release_group_mbid = (
                    release_to_rg.get(track.caa_release_mbid, "") if track.caa_release_mbid else None
                )

                cover_url: str | None = None
                if release_group_mbid:
                    cover_url = release_group_cover_url(release_group_mbid, size=250)
                elif track.caa_release_mbid:
                    cover_url = release_cover_url(track.caa_release_mbid, size=250)

                tracks.append(WeeklyExplorationTrack(
                    title=track.title,
                    artist_name=track.creator,
                    album_name=track.album,
                    recording_mbid=track.recording_mbid,
                    artist_mbid=artist_mbid,
                    release_group_mbid=release_group_mbid or None,
                    cover_url=cover_url,
                    duration_ms=track.duration_ms,
                ))

            return WeeklyExplorationSection(
                title=playlist.title,
                playlist_date=playlist.date,
                tracks=tracks,
                source_url=newest.get("identifier", ""),
            )
        except Exception as exc:  # noqa: BLE001
            logger.warning("Failed to build weekly exploration: %s", exc)
            return None
