package de.krisenvorrat.app.ui.update

import android.content.Context
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import de.krisenvorrat.app.BuildConfig
import de.krisenvorrat.app.domain.model.UpdateCheckResult
import de.krisenvorrat.app.domain.repository.UpdateRepository
import de.krisenvorrat.app.domain.usecase.ApkInstaller
import de.krisenvorrat.app.domain.usecase.CheckForUpdateUseCase
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import java.io.File
import javax.inject.Inject

@HiltViewModel
internal class UpdateViewModel @Inject constructor(
    private val checkForUpdateUseCase: CheckForUpdateUseCase,
    private val updateRepository: UpdateRepository,
    private val apkInstaller: ApkInstaller,
    @ApplicationContext private val context: Context
) : ViewModel() {

    private val _uiState = MutableStateFlow(UpdateUiState())
    val uiState: StateFlow<UpdateUiState> = _uiState.asStateFlow()

    init {
        checkForUpdate()
    }

    fun checkForUpdate() {
        viewModelScope.launch {
            _uiState.update { it.copy(status = UpdateStatus.Checking) }
            when (val result = checkForUpdateUseCase(BuildConfig.VERSION_CODE)) {
                is UpdateCheckResult.UpdateAvailable -> {
                    _uiState.update {
                        it.copy(
                            status = UpdateStatus.Available(
                                versionName = result.versionInfo.versionName,
                                apkUrl = result.versionInfo.apkUrl
                            )
                        )
                    }
                }
                is UpdateCheckResult.UpToDate,
                is UpdateCheckResult.NotConfigured -> {
                    _uiState.update { it.copy(status = UpdateStatus.Hidden) }
                }
                is UpdateCheckResult.Error -> {
                    _uiState.update { it.copy(status = UpdateStatus.Hidden) }
                }
            }
        }
    }

    fun startDownload() {
        val status = _uiState.value.status
        if (status !is UpdateStatus.Available) return

        val apkUrl = status.apkUrl
        val versionName = status.versionName
        val targetFile = File(context.cacheDir, "update/app-latest.apk")

        viewModelScope.launch {
            _uiState.update { it.copy(status = UpdateStatus.Downloading(0f)) }

            updateRepository.downloadApk(
                apkUrl = apkUrl,
                targetFile = targetFile,
                onProgress = { progress ->
                    _uiState.update { it.copy(status = UpdateStatus.Downloading(progress)) }
                }
            ).fold(
                onSuccess = {
                    _uiState.update {
                        it.copy(status = UpdateStatus.ReadyToInstall(versionName))
                    }
                    installApk(targetFile)
                },
                onFailure = { error ->
                    _uiState.update {
                        it.copy(status = UpdateStatus.Error(
                            error.message ?: "Download fehlgeschlagen"
                        ))
                    }
                }
            )
        }
    }

    fun dismiss() {
        _uiState.update { it.copy(status = UpdateStatus.Hidden) }
    }

    private fun installApk(file: File) {
        try {
            apkInstaller.install(file)
        } catch (_: Exception) {
            _uiState.update {
                it.copy(status = UpdateStatus.Error("Installation konnte nicht gestartet werden"))
            }
        }
    }
}
