import AppKit
import Foundation
import Observation

@Observable
@MainActor
public final class AppModel {
    public let settings: SettingsStore
    public let library: StationLibrary
    public let playback: PlaybackController
    let artwork: StationArtworkLoader
    private let nowPlayingArtwork: NowPlayingArtworkResolver

    public convenience init() {
        self.init(settings: SettingsStore(), persistence: PersistenceStore())
    }

    init(
        settings: SettingsStore = SettingsStore(),
        persistence: PersistenceStore = PersistenceStore()
    ) {
        self.settings = settings
        let client = RadioBrowserClient(baseURL: settings.baseURL, cacheDirectory: persistence.apiCacheDirectory)
        library = StationLibrary(client: client, persistence: persistence)
        let artworkLoader = StationArtworkLoader(cacheDirectory: persistence.cacheDirectory)
        artwork = artworkLoader
        nowPlayingArtwork = NowPlayingArtworkResolver(cacheDirectory: persistence.cacheDirectory, faviconLoader: artworkLoader)
        playback = PlaybackController(artworkProvider: { [weak nowPlayingArtwork] station, artist, title in
            nowPlayingArtwork?.resolve(artist: artist, title: title, station: station) ?? BearWaveAssets.image(named: "bearwave") ?? NSImage()
        })
        nowPlayingArtwork.onArtworkLoaded = { [weak playback] in
            playback?.refreshNowPlaying()
        }
        playback.onMetadataChanged = { [weak nowPlayingArtwork] artist, title, station in
            nowPlayingArtwork?.fetchArtwork(artist: artist, title: title, station: station)
        }
        playback.volume = library.volume
        library.updateBaseURL(settings.baseURL)
    }

    public func start() async {
        await library.load(.top)
        if settings.resumeOnLaunch, let station = library.resumeStation() {
            play(station)
        }
    }

    public func play(_ station: RadioStation) {
        library.recordPlayback(station)
        playback.play(station)
        nowPlayingArtwork.fetchArtwork(
            artist: playback.currentTrackArtist.isEmpty ? nil : playback.currentTrackArtist,
            title: playback.currentTrackTitle.isEmpty ? nil : playback.currentTrackTitle,
            station: station
        )
    }

    public func resumeLastStation() {
        guard let station = library.resumeStation() else { return }
        play(station)
    }

    public func setVolume(_ value: Double) {
        playback.volume = value
        library.saveVolume(value)
    }

    public func applySettings() {
        library.updateBaseURL(settings.baseURL)
    }

    public func quit() {
        playback.stop()
        nowPlayingArtwork.fetchArtwork(artist: nil, title: nil, station: nil)
    }
}
