//
//  AppleMusicCoordinator.swift
//  DashSmash
//
//  Wraps MusicKit for the Apple Music catalog search + ApplicationMusicPlayer
//  playback used by the "play to a real song" flow. Available on iOS 15+.
//

import Foundation
import MusicKit

@MainActor
final class AppleMusicCoordinator {

    enum AuthorizationOutcome {
        case authorized
        case denied
        case restricted
        case notDetermined
    }

    static let shared = AppleMusicCoordinator()
    private init() {}

    // MARK: - Authorization

    func authorize() async -> AuthorizationOutcome {
        let status = await MusicAuthorization.request()
        switch status {
        case .authorized:    return .authorized
        case .denied:        return .denied
        case .restricted:    return .restricted
        case .notDetermined: return .notDetermined
        @unknown default:    return .denied
        }
    }

    var isAuthorized: Bool {
        MusicAuthorization.currentStatus == .authorized
    }

    // MARK: - Search

    func searchSongs(query: String, limit: Int = 20) async throws -> [Song] {
        var request = MusicCatalogSearchRequest(term: query, types: [Song.self])
        request.limit = limit
        let response = try await request.response()
        return Array(response.songs)
    }

    /// Re-fetch a song by its MusicKit ID (used when replaying a saved level).
    func fetchSong(id: String) async throws -> Song? {
        let request = MusicCatalogResourceRequest<Song>(
            matching: \.id, equalTo: MusicItemID(id)
        )
        let response = try await request.response()
        return response.items.first
    }

    // MARK: - Playback

    private let player = ApplicationMusicPlayer.shared

    func play(song: Song) async throws {
        // Reset queue to just this song and start from the beginning.
        player.queue = [song]
        try await player.prepareToPlay()
        try await player.play()
    }

    func pause() {
        if player.state.playbackStatus == .playing {
            player.pause()
        }
    }

    func stop() {
        player.stop()
    }

    /// Restart the currently queued song from beat 0.
    func restartFromBeginning() async throws {
        player.playbackTime = 0
        try await player.play()
    }

    var playbackTime: TimeInterval {
        player.playbackTime
    }
}
