import Testing
import Foundation
@testable import Music

@MainActor
struct PlayerViewModelTests {
    private func makeTracks(_ count: Int) -> [Track] {
        (0..<count).map { i in
            Track.fixture(
                id: Int64(i + 1),
                fileURL: "/track\(i).mp3",
                title: "Track \(i)"
            )
        }
    }

    // Sets the queue and plays a track, verifies current track and index are set.
    @Test func playTrackSetsCurrentTrackAndIndex() {
        let vm = PlayerViewModel(audio: AudioService(), db: nil)
        let tracks = makeTracks(5)
        vm.setQueue(tracks)
        vm.play(tracks[2])

        #expect(vm.currentTrack?.id == 3)
        #expect(vm.currentIndex == 2)
    }

    // Calls next() and verifies it advances to the next track.
    @Test func nextAdvancesToNextTrack() {
        let vm = PlayerViewModel(audio: AudioService(), db: nil)
        let tracks = makeTracks(5)
        vm.setQueue(tracks)
        vm.play(tracks[0])
        vm.next()

        #expect(vm.currentTrack?.id == 2)
        #expect(vm.currentIndex == 1)
    }

    // Calls next() on the last track and verifies it stops (no wrap for v1).
    @Test func nextAtEndStops() {
        let vm = PlayerViewModel(audio: AudioService(), db: nil)
        let tracks = makeTracks(3)
        vm.setQueue(tracks)
        vm.play(tracks[2])
        vm.next()

        #expect(vm.currentTrack == nil)
    }

    // Calls previous() and verifies it goes to the previous track.
    @Test func previousGoesToPreviousTrack() {
        let vm = PlayerViewModel(audio: AudioService(), db: nil)
        let tracks = makeTracks(5)
        vm.setQueue(tracks)
        vm.play(tracks[3])
        vm.previous()

        #expect(vm.currentTrack?.id == 3)
    }

    // Calls previous() on the first track and verifies it stays at the first track.
    @Test func previousAtStartStaysAtFirst() {
        let vm = PlayerViewModel(audio: AudioService(), db: nil)
        let tracks = makeTracks(3)
        vm.setQueue(tracks)
        vm.play(tracks[0])
        vm.previous()

        #expect(vm.currentTrack?.id == 1)
        #expect(vm.currentIndex == 0)
    }

    // Enables shuffle and verifies the shuffled queue contains all tracks
    // and starts with the current track.
    @Test func shuffleContainsAllTracksStartingWithCurrent() {
        let vm = PlayerViewModel(audio: AudioService(), db: nil)
        let tracks = makeTracks(20)
        vm.setQueue(tracks)
        vm.play(tracks[5])
        vm.toggleShuffle()

        #expect(vm.isShuffled == true)
        #expect(vm.currentTrack?.id == 6)

        let shuffledIds = Set(vm.queue.map { $0.id })
        let originalIds = Set(tracks.map { $0.id })
        #expect(shuffledIds == originalIds)
    }

    // Disables shuffle and verifies the queue returns to original order
    // and current track is preserved.
    @Test func unshuffleRestoresOriginalOrder() {
        let vm = PlayerViewModel(audio: AudioService(), db: nil)
        let tracks = makeTracks(10)
        vm.setQueue(tracks)
        vm.play(tracks[3])
        vm.toggleShuffle()
        vm.toggleShuffle()

        #expect(vm.isShuffled == false)
        #expect(vm.currentTrack?.id == 4)
        #expect(vm.queue.map { $0.id } == tracks.map { $0.id })
    }
}
