package com.fabledsword.minstrel.library.data

import com.fabledsword.minstrel.cache.db.entities.CachedAlbumEntity
import com.fabledsword.minstrel.cache.db.entities.CachedArtistEntity
import com.fabledsword.minstrel.cache.db.entities.CachedTrackEntity
import com.fabledsword.minstrel.models.AlbumRef
import com.fabledsword.minstrel.models.ArtistRef
import com.fabledsword.minstrel.models.TrackRef
import com.fabledsword.minstrel.models.wire.AlbumDetailWire
import com.fabledsword.minstrel.models.wire.AlbumWire
import com.fabledsword.minstrel.models.wire.ArtistDetailWire
import com.fabledsword.minstrel.models.wire.ArtistWire
import com.fabledsword.minstrel.models.wire.TrackWire
import com.fabledsword.minstrel.shared.millisToSeconds
import com.fabledsword.minstrel.shared.secondsToMillis

// Wire to Entity — used after a successful sync/fetch to persist into Room.
// Entity fields are a subset of wire fields (display names + sort keys);
// fields the entity doesn't store are simply dropped.

fun ArtistWire.toEntity(): CachedArtistEntity =
    CachedArtistEntity(
        id = id,
        name = name,
        sortName = sortName,
    )

fun AlbumWire.toEntity(): CachedAlbumEntity =
    CachedAlbumEntity(
        id = id,
        artistId = artistId,
        title = title,
        sortTitle = sortTitle,
    )

fun TrackWire.toEntity(): CachedTrackEntity =
    CachedTrackEntity(
        id = id,
        albumId = albumId,
        artistId = artistId,
        title = title,
        durationMs = durationSec.secondsToMillis(),
        trackNumber = trackNumber,
        discNumber = discNumber,
    )

// Detail-wire to Entity — drops the embedded array; the embedded items
// are persisted separately via the regular wire mappers in the repository.

fun ArtistDetailWire.toArtistEntity(): CachedArtistEntity =
    CachedArtistEntity(
        id = id,
        name = name,
        sortName = sortName,
    )

fun AlbumDetailWire.toAlbumEntity(): CachedAlbumEntity =
    CachedAlbumEntity(
        id = id,
        artistId = artistId,
        title = title,
        sortTitle = sortTitle,
    )

// Entity to Domain — what ViewModels actually consume. The cache is the
// source of truth for cache-first reads; mapping to a domain type here
// keeps Room types out of the UI layer.

fun CachedArtistEntity.toDomain(coverAlbumId: String = ""): ArtistRef =
    ArtistRef(
        id = id,
        name = name,
        sortName = sortName,
        coverAlbumId = coverAlbumId,
    )

fun CachedAlbumEntity.toDomain(artistName: String = ""): AlbumRef =
    AlbumRef(
        id = id,
        title = title,
        artistId = artistId,
        sortTitle = sortTitle,
        artistName = artistName,
    )

fun CachedTrackEntity.toDomain(
    albumTitle: String = "",
    artistName: String = "",
): TrackRef =
    TrackRef(
        id = id,
        title = title,
        albumId = albumId,
        artistId = artistId,
        albumTitle = albumTitle,
        artistName = artistName,
        trackNumber = trackNumber,
        discNumber = discNumber,
        durationSec = durationMs.millisToSeconds(),
        // Deterministic from track id; matches the server's stream_url
        // (internal/api/convert.go:75 streamURL builder). Cached rows
        // didn't carry streamUrl before, which left MetadataProvider-
        // sourced tracks (Home Most Played, etc.) unplayable when their
        // queue was set on tap.
        streamUrl = "/api/tracks/$id/stream",
    )

// Wire to Domain — for fresh server responses that bypass the cache
// (e.g. a not-yet-cached search hit). Same field set as Entity to
// Domain plus the wire-only fields (albumTitle, artistName, streamUrl).

fun TrackWire.toDomain(): TrackRef =
    TrackRef(
        id = id,
        title = title,
        albumId = albumId,
        artistId = artistId,
        albumTitle = albumTitle,
        artistName = artistName,
        trackNumber = trackNumber,
        discNumber = discNumber,
        durationSec = durationSec,
        streamUrl = streamUrl,
    )

fun ArtistWire.toDomain(): ArtistRef =
    ArtistRef(
        id = id,
        name = name,
        sortName = sortName,
        albumCount = albumCount,
        coverUrl = coverUrl,
    )

fun AlbumWire.toDomain(): AlbumRef =
    AlbumRef(
        id = id,
        title = title,
        artistId = artistId,
        sortTitle = sortTitle,
        artistName = artistName,
        year = year,
        trackCount = trackCount,
        durationSec = durationSec,
        coverUrl = coverUrl,
    )
