package com.seven.ikar.kotlin.core.update

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.provider.Settings

class ArgusAppUpdateManager(
    private val context: Context,
    private val client: ArgusAppUpdateClient = ArgusAppUpdateClient(),
    private val installer: ArgusAppUpdateInstaller = ArgusAppUpdateInstaller(context),
    private val preferences: ArgusAppUpdatePreferences = ArgusAppUpdatePreferences(context)
) {
    fun canRequestPackageInstalls(): Boolean =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.packageManager.canRequestPackageInstalls()
        } else {
            true
        }

    fun buildUnknownSourcesIntent(): Intent =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            Intent(
                Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
                Uri.parse("package:${context.packageName}")
            )
        } else {
            Intent(Settings.ACTION_SECURITY_SETTINGS)
        }

    fun loadLastInstallerEvent(): AppUpdateInstallerEvent? =
        preferences.loadLastInstallerEvent()

    fun buildDownloadTargetFile(update: AvailableIkarUpdate) =
        ArgusAppUpdateCache.buildDownloadTargetFile(context, update)

    fun checkForUpdate(
        config: ArgusAppUpdateConfig,
        installedApp: InstalledIkarApp
    ): AppUpdateCheckResult =
        try {
            val manifest = client.fetchManifest(config)
                ?: return AppUpdateCheckResult.NotPublished(
                    "На сервере Argus нет совместимого релиза для ${config.slug}."
                )

            val manifestPackageName = manifest.androidPackageName?.trim()
            if (manifestPackageName.isNullOrBlank()) {
                return AppUpdateCheckResult.Incompatible(
                    "В карточке Argus не указан androidPackageName."
                )
            }

            if (!manifestPackageName.equals(installedApp.packageName, ignoreCase = false)) {
                return AppUpdateCheckResult.Incompatible(
                    "Argus отдаёт пакет $manifestPackageName, а текущее приложение имеет пакет ${installedApp.packageName}."
                )
            }

            if (!manifest.release.packageKind.equals("apk", ignoreCase = true)) {
                return AppUpdateCheckResult.Incompatible(
                    "Argus отдал packageKind=${manifest.release.packageKind}, а updater поддерживает только APK."
                )
            }

            val remoteVersionCode = manifest.release.androidVersionCode
                ?: return AppUpdateCheckResult.Incompatible(
                    "Argus не вернул androidVersionCode для релиза."
                )

            if (remoteVersionCode <= installedApp.versionCode) {
                return AppUpdateCheckResult.UpToDate(manifest)
            }

            AppUpdateCheckResult.UpdateAvailable(
                AvailableIkarUpdate(
                    config = config,
                    installedApp = installedApp,
                    manifest = manifest
                )
            )
        } catch (error: Exception) {
            AppUpdateCheckResult.Failed(
                reason = error.message ?: "Не удалось проверить наличие обновления в Argus.",
                cause = error
            )
        }

    fun downloadAndInstall(update: AvailableIkarUpdate): AppUpdateSubmissionResult =
        try {
            val targetFile = buildDownloadTargetFile(update)
            ArgusAppUpdateCache.deleteStaleDownloads(context, targetFile)
            val apkFile = client.downloadRelease(update, targetFile)
            installer.submitInstall(apkFile, update)
        } catch (error: Exception) {
            AppUpdateSubmissionResult.Rejected(
                error.message ?: "Не удалось скачать или запустить установку обновления."
            )
        }
}
