"""Entity → Subsonic child-dict mappers (presentation only).

Pure functions turning domain entities into the attribute dicts the envelope
serializer renders as ``<artist>`` / ``<album>`` / ``<song>`` elements (or their
JSON equivalents). No business logic — they only reshape and rename.
"""

import datetime as dt
from typing import Any

from app.api.rest.ids import encode_album, encode_artist, encode_track
from app.domain.entities import Album, Artist, Track

# Suffix → MIME, for the ``contentType``/``suffix`` song attributes. A
# presentation detail (mirrors StreamingService's content-type negotiation).
_CONTENT_TYPE: dict[str, str] = {
    "mp3": "audio/mpeg",
    "flac": "audio/flac",
    "m4a": "audio/mp4",
    "aac": "audio/aac",
    "ogg": "audio/ogg",
    "opus": "audio/ogg",
    "wav": "audio/wav",
    "aiff": "audio/aiff",
    "aif": "audio/aiff",
}


def iso(value: dt.datetime) -> str:
    return value.astimezone(dt.UTC).strftime("%Y-%m-%dT%H:%M:%S.000Z")


def content_type_for(file_format: str) -> str:
    return _CONTENT_TYPE.get(file_format.lower(), "application/octet-stream")


def artist_dict(artist: Artist, *, album_count: int) -> dict[str, Any]:
    return {
        "id": encode_artist(artist.id),
        "name": artist.name,
        "albumCount": album_count,
        "coverArt": encode_artist(artist.id),
    }


def album_dict(
    album: Album,
    artist: Artist | None,
    *,
    song_count: int,
    duration: int | None = None,
) -> dict[str, Any]:
    return {
        "id": encode_album(album.id),
        "name": album.title,
        "title": album.title,
        "artist": artist.name if artist is not None else None,
        "artistId": encode_artist(album.artist_id),
        "coverArt": encode_album(album.id),
        "songCount": song_count,
        "duration": duration,
        "created": iso(album.created_at),
        "year": album.year,
    }


def song_dict(
    track: Track,
    artist: Artist | None,
    album: Album | None,
) -> dict[str, Any]:
    cover = encode_album(track.album_id) if track.album_id is not None else encode_track(track.id)
    return {
        "id": encode_track(track.id),
        "parent": encode_album(track.album_id) if track.album_id is not None else None,
        "isDir": False,
        "title": track.title,
        "album": album.title if album is not None else None,
        "artist": artist.name if artist is not None else None,
        "albumId": encode_album(track.album_id) if track.album_id is not None else None,
        "artistId": encode_artist(track.artist_id),
        "coverArt": cover,
        "size": track.file_size,
        "contentType": content_type_for(track.file_format),
        "suffix": track.file_format,
        "duration": track.duration_seconds,
        "year": track.year,
        "genre": track.genre,
        "created": iso(track.created_at),
        "type": "music",
        "isVideo": False,
    }
