"""Album endpoints."""

import uuid

from fastapi import APIRouter, Query
from fastapi.responses import StreamingResponse

from app.api.covers import stream_cover
from app.api.deps import (
    AlbumRepoDep,
    ArtistRepoDep,
    CurrentUser,
    FileStorageDep,
    StreamUser,
    TrackRepoDep,
)
from app.api.schemas.album import AlbumOut
from app.api.schemas.pagination import PagedResponse
from app.api.schemas.track import TrackOut
from app.api.v1.tracks import _build_track_out
from app.domain.entities.album import Album
from app.domain.entities.track import Artist
from app.domain.errors import NotFoundError

router = APIRouter(prefix="/albums", tags=["albums"])


async def _build_album_out(
    albums: list[Album],
    artists: dict[uuid.UUID, Artist],
    track_counts: dict[uuid.UUID, int],
) -> list[AlbumOut]:
    return [
        AlbumOut(
            id=a.id,
            title=a.title,
            artist_id=a.artist_id,
            artist_name=artists[a.artist_id].name if a.artist_id in artists else "Unknown Artist",
            year=a.year,
            track_count=track_counts.get(a.id, 0),
            has_cover=bool(a.cover_path),
            created_at=a.created_at,
        )
        for a in albums
    ]


@router.get("")
async def list_albums(
    album_repo: AlbumRepoDep,
    artist_repo: ArtistRepoDep,
    _: CurrentUser,
    artist_id: uuid.UUID | None = None,
    q: str | None = None,
    limit: int = Query(50, ge=1, le=200),
    offset: int = Query(0, ge=0),
) -> PagedResponse[AlbumOut]:
    albums = await album_repo.list(artist_id=artist_id, q=q, limit=limit, offset=offset)
    total = await album_repo.count(artist_id=artist_id, q=q)

    artist_ids = list({a.artist_id for a in albums})
    artists = {a.id: a for a in await artist_repo.get_many(artist_ids)}
    track_counts = await album_repo.track_count_many([a.id for a in albums])

    items = await _build_album_out(albums, artists, track_counts)
    return PagedResponse(items=items, total=total, limit=limit, offset=offset)


@router.get("/{album_id}")
async def get_album(
    album_id: uuid.UUID,
    album_repo: AlbumRepoDep,
    artist_repo: ArtistRepoDep,
    _: CurrentUser,
) -> AlbumOut:
    album = await album_repo.get_by_id(album_id)
    if album is None:
        raise NotFoundError(f"Album {album_id} not found.")

    artists = {a.id: a for a in await artist_repo.get_many([album.artist_id])}
    track_counts = await album_repo.track_count_many([album.id])

    items = await _build_album_out([album], artists, track_counts)
    return items[0]


@router.get("/{album_id}/tracks")
async def get_album_tracks(
    album_id: uuid.UUID,
    track_repo: TrackRepoDep,
    artist_repo: ArtistRepoDep,
    album_repo: AlbumRepoDep,
    _: CurrentUser,
    limit: int = Query(50, ge=1, le=200),
    offset: int = Query(0, ge=0),
) -> PagedResponse[TrackOut]:
    album = await album_repo.get_by_id(album_id)
    if album is None:
        raise NotFoundError(f"Album {album_id} not found.")

    tracks = await track_repo.list(
        artist_id=None,
        album_id=album_id,
        q=None,
        sort_by="title",
        order="asc",
        limit=limit,
        offset=offset,
    )
    total = await track_repo.count(artist_id=None, album_id=album_id, q=None)

    artist_ids = list({t.artist_id for t in tracks})
    artists = {a.id: a for a in await artist_repo.get_many(artist_ids)}
    albums = {album.id: album}

    items = await _build_track_out(tracks, artists, albums)
    return PagedResponse(items=items, total=total, limit=limit, offset=offset)


@router.get("/{album_id}/cover")
async def get_album_cover(
    album_id: uuid.UUID,
    album_repo: AlbumRepoDep,
    storage: FileStorageDep,
    _: StreamUser,
) -> StreamingResponse:
    # ``<img>`` can't send a bearer header → StreamUser accepts ``?token=``.
    album = await album_repo.get_by_id(album_id)
    if album is None or not album.cover_path:
        raise NotFoundError("Cover not found.")
    return await stream_cover(storage, album.cover_path)
