/**
 * Tests for the slim /api/tracks projection (routes/api/trackProjection.ts).
 *
 * The Collection view fetches the whole library and only renders a handful of
 * fields, so ?slim=true projects each Track down to those fields + stream URLs
 * and drops the heavy columns (fingerprint, musicbrainz_* IDs, replaygain,
 * lyrics, …). These cover the projection contract: essential fields kept with
 * the right values + fallbacks, and the heavy fields actually gone (the whole
 * point — a regression here silently re-bloats the payload ~6x).
 */ import { describe, it, expect } from "@jest/globals";
import { getArtworkUrl, toSlimLocalTrack } from "../routes/api/trackProjection.js";
// A fully-populated Track, including the heavy columns slim mode must drop.
function makeFullTrack(overrides = {}) {
    return {
        path: "/music/Artist/Album/01 Title.flac",
        track_id: "uuid-1234",
        title: "Title",
        artist: "Artist",
        album: "Album",
        albumartist: "Album Artist",
        duration: 215.4,
        size: 41_000_000,
        modified: 1_700_000_000,
        isrc: "US-ABC-12-34567",
        fingerprint: "a".repeat(3000),
        musicbrainz_id: "mb-recording-id",
        metadata_confidence: 0.95,
        artwork_hash: "hash123",
        last_scanned: 1_700_000_500,
        playCount: 7,
        lastPlayed: 1_700_000_900,
        year: 2021,
        genre: [
            "Electronic",
            "House"
        ],
        bitrate: 1_000_000,
        track_no: 1,
        disk_no: 1,
        replaygain_track_gain: -6.5,
        replaygain_track_peak: 0.98,
        musicbrainz_albumid: "mb-album-id",
        musicbrainz_artistid: "mb-artist-id",
        composer: "Composer",
        lyrics: "line one\nline two",
        lyrics_synced: "[00:00.00] line one",
        ...overrides
    };
}
describe("toSlimLocalTrack — essential fields kept", ()=>{
    it("keeps the rendered fields with correct values + dual artwork/stream aliases", ()=>{
        const slim = toSlimLocalTrack(makeFullTrack());
        expect(slim).toMatchObject({
            path: "/music/Artist/Album/01 Title.flac",
            title: "Title",
            artist: "Artist",
            album: "Album",
            albumartist: "Album Artist",
            duration: 215.4,
            year: 2021,
            track_no: 1,
            trackNumber: 1,
            disk_no: 1,
            artwork_hash: "hash123",
            modified: 1_700_000_000,
            playCount: 7,
            lastPlayed: 1_700_000_900,
            genre: [
                "Electronic",
                "House"
            ],
            source: "local"
        });
        // artwork + artwork_url are aliases; url + stream_url are aliases.
        expect(slim.artwork_url).toBe("/api/sound/artwork/hash123");
        expect(slim.artwork).toBe(slim.artwork_url);
        expect(slim.url).toBe(slim.stream_url);
    });
    it("URL-encodes the path in the stream URLs", ()=>{
        const slim = toSlimLocalTrack(makeFullTrack({
            path: "/music/A & B/Track #1.flac"
        }));
        expect(slim.stream_url).toBe("/api/stream/" + encodeURIComponent("/music/A & B/Track #1.flac"));
        expect(slim.stream_url).not.toContain(" "); // genuinely encoded, no raw spaces
        expect(slim.stream_url).not.toContain("#");
    });
});
describe("toSlimLocalTrack — heavy fields dropped", ()=>{
    it("omits the bulky columns the Collection view never reads", ()=>{
        const slim = toSlimLocalTrack(makeFullTrack());
        for (const heavy of [
            "fingerprint",
            "isrc",
            "musicbrainz_id",
            "musicbrainz_albumid",
            "musicbrainz_artistid",
            "size",
            "last_scanned",
            "metadata_confidence",
            "bitrate",
            "replaygain_track_gain",
            "replaygain_track_peak",
            "composer",
            "lyrics",
            "lyrics_synced",
            "track_id"
        ]){
            expect(slim).not.toHaveProperty(heavy);
        }
    });
    it("is materially smaller than the full track once serialized", ()=>{
        const full = makeFullTrack();
        const slimJson = JSON.stringify(toSlimLocalTrack(full));
        const fullJson = JSON.stringify(full);
        // The 3KB fingerprint alone dominates; slim should be a small fraction.
        expect(slimJson.length).toBeLessThan(fullJson.length / 3);
    });
});
describe("toSlimLocalTrack — fallbacks", ()=>{
    it("applies Unknown fallbacks and zeroes for null/absent fields", ()=>{
        const slim = toSlimLocalTrack(makeFullTrack({
            title: null,
            artist: null,
            album: null,
            duration: null,
            artwork_hash: null,
            playCount: undefined,
            lastPlayed: undefined
        }));
        expect(slim.title).toBe("Unknown Title");
        expect(slim.artist).toBe("Unknown Artist");
        expect(slim.album).toBe("Unknown Album");
        expect(slim.duration).toBe(0);
        expect(slim.playCount).toBe(0);
        expect(slim.lastPlayed).toBeUndefined();
        // No artwork hash → null artwork URLs (not a broken /api/sound/artwork/null).
        expect(slim.artwork_url).toBeNull();
        expect(slim.artwork).toBeNull();
    });
});
describe("getArtworkUrl", ()=>{
    it("returns null for empty/absent hashes", ()=>{
        expect(getArtworkUrl(null)).toBeNull();
        expect(getArtworkUrl(undefined)).toBeNull();
        expect(getArtworkUrl("")).toBeNull();
    });
    it("builds the proxy-relative URL for a real hash", ()=>{
        expect(getArtworkUrl("abc123")).toBe("/api/sound/artwork/abc123");
    });
});

//# sourceMappingURL=trackProjection.test.js.map