package com.gh.common.simulator

import android.annotation.SuppressLint
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.net.Uri
import android.text.TextUtils
import com.gh.common.constant.Config
import com.gh.common.util.ApkActiveUtils
import com.gh.common.util.LogUtils
import com.gh.common.util.PackageUtils
import com.gh.download.DownloadManager
import com.gh.gamecenter.common.callback.BiCallback
import com.gh.gamecenter.common.json.json
import com.gh.gamecenter.common.retrofit.BiResponse
import com.gh.gamecenter.common.retrofit.EmptyResponse
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.core.utils.SPUtils
import com.gh.gamecenter.core.utils.TimeUtils
import com.gh.gamecenter.core.utils.ToastUtils
import com.gh.gamecenter.core.utils.UrlFilterUtils
import com.gh.gamecenter.entity.GameEntity
import com.gh.gamecenter.entity.SimulatorGameRecordEntity
import com.gh.gamecenter.login.user.UserManager
import com.gh.gamecenter.retrofit.RetrofitManager
import com.gh.gamecenter.room.AppDatabase
import com.halo.assistant.HaloApp
import com.lightgame.download.DownloadDao
import com.lightgame.download.DownloadEntity
import com.lightgame.download.FileUtils
import com.lightgame.utils.AppManager
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import okhttp3.ResponseBody
import org.json.JSONArray
import java.io.ByteArrayOutputStream
import java.io.File
import java.util.*

object SimulatorGameManager {

    private val mGamePath by lazy { FileUtils.getDownloadPath(HaloApp.getInstance().application, "emulator_game") }

    const val SIMULATOR_UPDATE_SHOW_ALERT_TAG = "simulator-update-show-alert"

    private val mSimulatorPackageNames by lazy {
        listOf(
            "com.gh.fbnemu",
            "com.gh.mame4droid",
            "com.gh.nesemu",
            "com.gh.ppsspp",
            "com.gh.gbaemu",
            "com.gh.gbcemu",
            "com.gh.snes9xplus"
        )
    }

    const val NEW_SIMULATOR_PACKAGE_NAME = "com.gh.retroemu" //新版本模拟器包名


    @JvmStatic
    //是否安装了新模拟器
    fun isNewSimulatorInstalled(context: Context?): Boolean {
        return PackageUtils.isInstalledFromAllPackage(context, NEW_SIMULATOR_PACKAGE_NAME)
    }

    @JvmStatic
    //是否安装了旧模拟器
    fun isOldSimulatorInstalled(context: Context?): Boolean {
        for (packageName in mSimulatorPackageNames) {
            if (PackageUtils.isInstalledFromAllPackage(context, packageName)) {
                return true
            }
        }
        return false
    }

    @JvmStatic
    fun getPathByType(type: String) = "${mGamePath}/${type}"

    @JvmStatic
    fun deleteLocalGames(names: List<String>) {
        val downloadEntityList = DownloadManager.getInstance().allDownloadEntity
        names.forEach { name ->
            val downloadEntity = downloadEntityList.find { it.name == name }
            if (downloadEntity != null) {
                val file = File(downloadEntity.path)
                if (file.exists()) {
                    file.delete()
                    DownloadDao.getInstance(HaloApp.getInstance().application).delete(downloadEntity.url)
                }
            }
        }
    }

    @JvmStatic
    fun deleteLocalGame(name: String) {
        val downloadEntityList = DownloadManager.getInstance().allDownloadEntity
        val downloadEntity = downloadEntityList.find { it.name == name }
        if (downloadEntity != null) {
            val file = File(downloadEntity.path)
            if (file.exists()) {
                file.delete()
                DownloadDao.getInstance(HaloApp.getInstance().application).delete(downloadEntity.url)
            }
        }
    }

    @JvmStatic
    fun findDownloadEntityByUrl(url: String?): DownloadEntity? {
        val downloadEntity = DownloadManager.getInstance().getDownloadEntityByUrl(url)
        if (downloadEntity != null) {
            val isFileCompleted = DownloadManager.getInstance().isDownloadCompleted(url)
            if (downloadEntity.isSimulatorGame() && isFileCompleted) {
                return downloadEntity
            }
        }
        return null
    }

    @JvmStatic
    fun isSimulatorGame(gameEntity: GameEntity) = gameEntity.category == "simulator"


    @JvmStatic
    fun launchSimulatorGame(downloadEntity: DownloadEntity, gameEntity: GameEntity) {
        val isInstalledNewSimulator = isNewSimulatorInstalled(HaloApp.getInstance().application)
        var packageName = gameEntity.simulator?.apk?.packageName
        var simulator = gameEntity.simulator

        if (isInstalledNewSimulator) {
            packageName = NEW_SIMULATOR_PACKAGE_NAME
            if (Config.getNewSimulatorEntitySetting() == null) {
                return
            }
            simulator = Config.getNewSimulatorEntitySetting()
        }
//        val version = simulator?.apk?.version
//        val versionFromInstalledApp = PackageUtils.getVersionNameByPackageName(packageName)
        val shouldShowUpdate = PackageUtils.isInstalledApkMatchedMd5(packageName, simulator?.apk?.md5)
        updateSimulatorConfigFile(gameId = gameEntity.id)
        if (shouldShowUpdate) {
            val showAlertTag = SPUtils.getString(SIMULATOR_UPDATE_SHOW_ALERT_TAG, "")
            val todayIsShow = showAlertTag == TimeUtils.getToday() //当天是否弹过
            if (!todayIsShow) {
                SimulatorDownloadManager.getInstance().showDownloadDialog(
                    AppManager.getInstance().recentActiveActivity, simulator,
                    SimulatorDownloadManager.SimulatorLocation.LAUNCH, gameEntity.id, gameEntity.name
                        ?: ""
                ) {
                    jumpToSimulator(downloadEntity, gameEntity)
                }
            } else {
                jumpToSimulator(downloadEntity, gameEntity)
            }
        } else {
            jumpToSimulator(downloadEntity, gameEntity)
        }
    }

    @SuppressLint("CheckResult")
    private fun jumpToSimulator(downloadEntity: DownloadEntity, gameEntity: GameEntity) {
        val isInstalledNewSimulator = isNewSimulatorInstalled(HaloApp.getInstance().application)
        if (isInstalledNewSimulator){
            NewSimulatorGameManager.launchGameViaSimulator(downloadEntity,gameEntity)
            return
        }
        val gameIcon = gameEntity.icon ?: gameEntity.rawIcon ?: ""
        Single.just(ImageUtils.getCachedUrl(gameIcon))
            .flatMap {
                getBitmapFormCache(it)
            }.map {
                BitmapUtils.compressBitmap(it, 100)
            }.map {
                val baos = ByteArrayOutputStream()
                it.compress(Bitmap.CompressFormat.WEBP, 100, baos)
                baos.toByteArray()
            }
            .compose(singleToMain())
            .subscribe({
                val intent = Intent()
                intent.data = Uri.fromFile(File(downloadEntity.path))
                if (gameEntity.simulatorType == "FBA" || gameEntity.simulatorType == "FBN") {
                    val apkEntity = gameEntity.getApk()[0]
                    intent.putExtra("rom_name", apkEntity.packageName)
                }
                intent.putExtra("default_path", downloadEntity.path.substring(0, downloadEntity.path.lastIndexOf('/')))
                intent.putExtra("game_type", gameEntity.simulatorType)
                intent.putExtra("title", downloadEntity.name)
                intent.putExtra("icon", gameIcon)
                intent.putExtra("iconStream", it)
                intent.putExtra("meta", LogUtils.getMetaObject().toString())
                intent.putExtra("simulatorId", gameEntity.simulator?.id)
                intent.putExtra("simulatorName", gameEntity.simulator?.name)
                intent.putExtra("gameId", gameEntity.id)

                val destActivity = "com.gh.emu.RequestPermissionActivity"
                intent.setClassName(gameEntity.simulator?.apk?.packageName ?: "", destActivity)
                try {
                    AppManager.getInstance().recentActiveActivity?.startActivity(intent)
                } catch (e: ActivityNotFoundException) {
                    ToastUtils.showToast("模拟器安装错误")
                }

                recordPlaySimulatorGames(gameEntity.id)
            }, {
                ToastUtils.showToast("跳转失败")
            })
    }

    fun getBitmapFormCache(url: String): Single<Bitmap> {
        return Single.create {
            ImageUtils.getBitmap(url, object : BiCallback<Bitmap, Boolean> {
                override fun onFirst(first: Bitmap) {
                    it.onSuccess(first)
                }

                override fun onSecond(second: Boolean) {
                    it.onError(Throwable("获取bitmap失败"))
                }
            })
        }
    }


    /**
     * 记录设备下载的模拟器游戏
     */
    @SuppressLint("CheckResult")
    @JvmStatic
    fun recordDownloadSimulatorGame(gameId: String, type: String) {
        val requestMap = hashMapOf<String, Any>()
        requestMap["game_id"] = gameId
        requestMap["package"] = "-"
        val body = requestMap.createRequestBodyAny()
        RetrofitManager.getInstance().api
            .downloadSimulatorGames(HaloApp.getInstance().gid, body)
            .compose(singleToMain())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    refreshSimulatorGame(gameId, type)
                }
            })
    }

    /**
     * 批量记录设备下载的模拟器游戏
     */
    @SuppressLint("CheckResult")
    @JvmStatic
    fun recordDownloadSimulatorGames() {
        val gameArray = JSONArray()
        val allGameList = AppDatabase.getInstance().simulatorGameDao().getAllSimulatorGame()
        for (game in allGameList) {
            if (!game.isDeleted) {
                gameArray.put(json {
                    "game_id" to game.id
                    "package" to "-"
                })
            }
        }

        if (gameArray.length() == 0) return

        RetrofitManager.getInstance().api
            .putDownloadSimulatorGames(HaloApp.getInstance().gid, gameArray.toRequestBody())
            .compose(singleToMain())
            .subscribe(EmptyResponse())
    }

    @SuppressLint("CheckResult")
    private fun refreshSimulatorGame(gameId: String, type: String) {
        val simulatorGameDao = AppDatabase.getInstance().simulatorGameDao()
        RetrofitManager.getInstance().api
            .getSimulatorGames(HaloApp.getInstance().gid, 1, getFilter(type))
            .compose(singleToMain())
            .subscribe(object : BiResponse<List<GameEntity>>() {
                override fun onSuccess(data: List<GameEntity>) {
                    val simulatorGameRecordList = ArrayList<SimulatorGameRecordEntity>()
                    data.forEach {
                        val entity = it.convertSimulatorGameRecordEntity()
                        entity.isRecentlyPlayed = it.id == gameId
                        simulatorGameRecordList.add(entity)
                    }
                    simulatorGameDao.addSimulatorGameList(simulatorGameRecordList)
                }
            })
    }

    private fun getFilter(type: String): String {
        return UrlFilterUtils.getFilterQuery("type", type)
    }

    /**
     * 标记已玩过
     */
    @SuppressLint("CheckResult")
    fun postPlayedGame(gameId: String, packageName: String) {
        if (!TextUtils.isEmpty(gameId) && UserManager.getInstance().isLoggedIn) {
            val requestMap = hashMapOf<String, Any>()
            requestMap["game_id"] = gameId
            requestMap["package"] = packageName
            val body = requestMap.toRequestBody()
            RetrofitManager.getInstance().api
                .postPlayedGame(UserManager.getInstance().userId, body)
                .compose(singleToMain())
                .subscribe(EmptyResponse())
        }
    }


    /**
     * 记录启动设备上的模拟器游戏
     */
    @SuppressLint("CheckResult")
    fun recordPlaySimulatorGames(gameId: String) {
        val requestMap = hashMapOf<String, Any>()
        requestMap["game_id"] = gameId
        requestMap["package"] = "-"
        val body = requestMap.createRequestBodyAny()
        RetrofitManager.getInstance().api
            .playedSimulatorGames(HaloApp.getInstance().gid, body)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(EmptyResponse())
    }

    /**
     * 删除设备下载模拟器游戏的记录
     */
    @SuppressLint("CheckResult")
    fun deleteSimulatorGame(gameId: String, callback: () -> Unit) {
        RetrofitManager.getInstance().api
            .deleteSimulatorGame(HaloApp.getInstance().gid, gameId)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    callback.invoke()
                }
            })
    }

    /**
     * 批量删除设备下载模拟器游戏的记录
     */
    @JvmStatic
    @SuppressLint("CheckResult")
    fun deleteSimulatorGames(gameIds: List<String>, callback: () -> Unit) {
        val requestMap = hashMapOf<String, Any>()
        requestMap["game_ids"] = gameIds
        RetrofitManager.getInstance().api
            .deleteSimulatorGames(HaloApp.getInstance().gid, requestMap.toRequestBody())
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : BiResponse<ResponseBody>() {
                override fun onSuccess(data: ResponseBody) {
                    callback.invoke()
                }
            })
    }

    /**
     * 批量删除设备下载模拟器游戏的记录
     */
    @JvmStatic
    @SuppressLint("CheckResult")
    fun deleteAllSimulatorGame() {
        RetrofitManager.getInstance().api
            .deleteAllSimulatorGame(HaloApp.getInstance().gid)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(EmptyResponse())
    }

    private fun updateSimulatorConfigFile(gameId: String) {
        RetrofitManager.getInstance()
            .api
            .getGameDigest(gameId)
            .map(ApkActiveUtils.filterMapper)
            .subscribeOn(Schedulers.io())
            .subscribe(object : Response<GameEntity>() {
                override fun onResponse(game: GameEntity?) {
                    game?.let {
                        if (!TextUtils.isEmpty(game.simulatorGameConfig)) {
                            val configFilePath = getPathByType(
                                game.simulatorType + "/cheat/" + game.getApk().firstOrNull()?.packageName + ".ini"
                            )
                            FileUtils.downloadAndUpdateFile(game.simulatorGameConfig, configFilePath)
                        }
                    }
                }
            })
    }
}