package com.fabledsword.minstrel.events

import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import com.fabledsword.minstrel.di.ApplicationScope
import com.fabledsword.minstrel.likes.data.LikesRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import javax.inject.Inject
import javax.inject.Singleton

/**
 * Maps incoming [LiveEvent]s to cross-screen state refreshes. Mirrors
 * `flutter_client/lib/shared/live_events_dispatcher.dart`. Activated
 * by force-@Inject in MinstrelApplication.
 *
 * Scope is deliberately narrow: this dispatcher only touches state
 * that's reachable from /shared (i.e. that has a Repository-level
 * refresh method). Screen-scoped state (PlaylistDetail for a
 * specific id, a single Request's status_changed) is opted into by
 * the screen's ViewModel subscribing to [EventsStream.events]
 * directly.
 *
 * Includes a [ProcessLifecycleOwner] foreground hook that
 * defensively re-runs the same refreshes — SSE catches up on its
 * own, but a long-backgrounded app can hit `onStart` before the
 * stream reconnects and the re-refresh avoids stale data flashing.
 */
@Singleton
class LiveEventsDispatcher @Inject constructor(
    private val eventsStream: EventsStream,
    private val likes: LikesRepository,
    @ApplicationScope private val scope: CoroutineScope,
) : DefaultLifecycleObserver {

    init {
        ProcessLifecycleOwner.get().lifecycle.addObserver(this)
        scope.launch {
            eventsStream.events.collect { e -> handle(e) }
        }
    }

    private fun handle(event: LiveEvent) {
        when (event.kind) {
            "track.liked",
            "track.unliked",
            "album.liked",
            "album.unliked",
            "artist.liked",
            "artist.unliked",
            -> refreshLikes()
        }
        // Other kinds (playlist.*, quarantine.*, request.status_changed,
        // scan.*) reach screen-scoped subscribers via EventsStream
        // directly. Add cross-screen cases here only when a new
        // Repository-level refresh becomes available.
    }

    override fun onStart(owner: LifecycleOwner) {
        // App returned to the foreground. SSE will catch up but might
        // not have reconnected yet; flush the cross-screen refreshes
        // defensively.
        refreshLikes()
    }

    private fun refreshLikes() {
        scope.launch {
            runCatching { likes.refreshIds() }
        }
    }
}
