package com.hermes.app

import android.content.Context
import android.os.Build
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.hermes.app.core.analytics.HermesAnalyticsTracker
import com.hermes.app.core.localization.HermesLocalizationStore
import com.hermes.app.core.media.HermesPlayerCoordinator
import com.hermes.app.core.network.HermesApiClient
import com.hermes.app.data.HermesRepository
import com.hermes.app.domain.HermesSessionStartRequest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import okhttp3.HttpUrl.Companion.toHttpUrl

class HermesAppContainer(context: Context) {
    val localizationStore = HermesLocalizationStore(context.applicationContext)
    val analyticsTracker = HermesAnalyticsTracker()
    val apiClient = HermesApiClient(BuildConfig.API_BASE_URL.toHttpUrl())
    val repository = HermesRepository(apiClient)
    val playerCoordinator = HermesPlayerCoordinator(context.applicationContext)
    private val analyticsScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
    private val analyticsFlushMutex = Mutex()
    private val analyticsSessionJob: Job
    private val analyticsTickerJob: Job

    init {
        analyticsSessionJob = analyticsScope.launch {
            repository.currentSession.filterNotNull().collect {
                flushAnalytics()
            }
        }

        analyticsTickerJob = analyticsScope.launch {
            while (isActive) {
                delay(5_000)
                flushAnalytics()
            }
        }
    }

    fun feedViewModelFactory(): ViewModelProvider.Factory = HermesViewModelFactory {
        com.hermes.app.feature.feed.FeedViewModel(repository, localizationStore, analyticsTracker)
    }

    fun roundViewModelFactory(): ViewModelProvider.Factory = HermesViewModelFactory {
        com.hermes.app.feature.round.RoundViewModel(repository, localizationStore, analyticsTracker, playerCoordinator)
    }

    fun sessionViewModelFactory(): ViewModelProvider.Factory = HermesViewModelFactory {
        com.hermes.app.feature.session.SessionViewModel(
            repository = repository,
            localizationStore = localizationStore,
            analyticsTracker = analyticsTracker,
            sessionRequestFactory = ::buildSessionStartRequest,
        )
    }

    private fun buildSessionStartRequest(localeCode: String): HermesSessionStartRequest {
        return HermesSessionStartRequest(
            localeCode = localeCode,
            devicePlatform = "android",
            deviceModel = Build.MODEL,
            osVersion = Build.VERSION.RELEASE,
            appVersion = BuildConfig.VERSION_NAME,
        )
    }

    suspend fun flushAnalytics() {
        analyticsFlushMutex.withLock {
            if (repository.currentSession.value == null) {
                return
            }

            val events = analyticsTracker.pendingEventsSnapshot()
            if (events.isEmpty()) {
                return
            }

            runCatching {
                repository.submitAnalyticsBatch(analyticsTracker.toBatchRequest(events))
            }.onSuccess {
                analyticsTracker.markDelivered(events.map { it.id }.toSet())
            }
        }
    }
}

class HermesViewModelFactory<T : ViewModel>(private val creator: () -> T) : ViewModelProvider.Factory {
    @Suppress("UNCHECKED_CAST")
    override fun <T : ViewModel> create(modelClass: Class<T>): T = creator() as T
}
