package com.secspace.lib.common.function

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.os.Environment
import android.util.Log
import com.secspace.lib.common.utils.ImeiUtil.uniqueId
import com.skr.activation.api.ActivationApi
import com.skr.activation.constant.Constant.*
import com.skr.activation.network.linstener.CheckActiveStatusListener
import com.skr.activation.network.linstener.CheckLocalActiveStatusListener
import com.skr.activation.network.linstener.GetSystemTimeListener
import com.skr.activation.utils.DesUtil
import com.skr.activation.utils.XmlUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.xmlpull.v1.XmlPullParserException
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.*
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine


const val PROBATION = "probation"
const val SP_TRIAL_ACTIVE_START_TIME = "trialActiveStartTime"
const val PROBATION_TIME: Long = 7 * 24 * 60 * 60 * 1000
//const val PROBATION_TIME: Long = 1 * 60 * 1000

object ActivationHelper {
    private const val TAG = "ActivationHelper"
    private val FILE_PATH = Environment.getExternalStorageDirectory().toString() + "/."
    private const val PROBATION_FILE_NAME = "probation.xml"
    private const val ACTIVATE_FILE_NAME = "activate.xml"

    fun active(context: Context, listener: ActivationListener, force: Boolean = false) {
        ActivationApi.getInstance().isActiveFromLocalAndNet(context.packageName, object : CheckLocalActiveStatusListener {
            override fun hasActivated() {
                listener.activated()
            }

            override fun needActivate() {
                Log.i(TAG, "needActivate")
                GlobalScope.launch(Dispatchers.Main) {
                    if (force) {
                        ActivationApi.getInstance().setUseNormalDialog(true)
                        ActivationApi.getInstance().startActivateActivity(context, context.packageName, false)
                        return@launch
                    }

                    val isProbationCreate = isProbationCreate(context)
                    if (isProbationCreate) {
                        val isProbation = isProbationFromLocal(context)
                        if (isProbation) {
                            listener.activated()
                        } else {
                            DialogManager.showBuyCodeDialog(context)
                        }
                    } else {
                        if (probation(context)) {
                            listener.activated()
                            return@launch
                        }
                        listener.activationFailed()
                    }
                }
            }
            override fun onError() {
                listener.activationFailed()
            }
        })
    }

    fun checkActivate(context: Context, listener: CheckActiveStatusListener?) {
        ActivationApi.getInstance().checkActivateCodeStatus(context.packageName, listener, false)
    }

    private suspend fun getCurrentTimeByNet(): Long = suspendCoroutine { cont ->
        ActivationApi.getInstance().getSystemTime(object : GetSystemTimeListener {
            override fun onTime(p0: Long) {
                cont.resume(p0)
            }

            override fun onError(p0: Throwable?) {
                cont.resume(-1L)
            }
        })
    }

    private fun isProbationCreate(context: Context): Boolean {
        return File(FILE_PATH + context.packageName, PROBATION_FILE_NAME).exists()
    }

    suspend fun isProbationFromLocal(context: Context): Boolean {
        return withContext(Dispatchers.IO) {
            val file = File(FILE_PATH + context.packageName, PROBATION_FILE_NAME)
            if (!file.exists()) {
                return@withContext false
            }
            val map: HashMap<String?, *>?
            map = try {
                XmlUtils.readMapXml(FileInputStream(file))
            } catch (e: XmlPullParserException) {
                Log.e(TAG, "ERROR: ${e.message}")
                return@withContext false
            } catch (e: IOException) {
                Log.e(TAG, "ERROR: ${e.message}")
                return@withContext false
            }
            if (map != null && map.containsKey(SP_TRIAL_ACTIVE_END_TIME)) {
                val endTime: Long = DesUtil.decrypt(map[SP_TRIAL_ACTIVE_END_TIME].toString()).toLong()
                val currentTime = getCurrentTimeByNet()
                if (currentTime == -1L) {
                    //  出异常不用处理
                    return@withContext true
                }
                if (currentTime > endTime) {
                    return@withContext false
                }
                return@withContext true
            }
            return@withContext false
        }
    }

    private suspend fun probation(context: Context): Boolean {
        val map: MutableMap<String?, String?> = HashMap()
        val currentTime = getCurrentTimeByNet()
        if (currentTime == -1L) {
            return false
        }
        val endTime = currentTime + PROBATION_TIME
        map[SP_IS_ACTIVE] = DesUtil.encrypt(PROBATION)
        map[SP_TRIAL_ACTIVE_END_TIME] = DesUtil.encrypt(endTime.toString())
        map[SP_ACTIVE_CODE] = DesUtil.encrypt("无")
        map[SP_TRIAL_ACTIVE_START_TIME] = DesUtil.encrypt(currentTime.toString())
        try {
            val fileDir = File(FILE_PATH + context.packageName)
            if (!fileDir.exists()) {
                fileDir.mkdirs()
            }
            val file = File(fileDir, PROBATION_FILE_NAME)
            if (!file.exists()) {
                file.createNewFile()
            }
            XmlUtils.writeMapXml(map, FileOutputStream(file))
        } catch (e: XmlPullParserException) {
            return false
        } catch (e: IOException) {
            return false
        }
        return true
    }

    private fun getValueByXmlKey(context: Context, key: String, fileName: String): String {
        val file = File(FILE_PATH + context.packageName, fileName)
        if (!file.exists()) {
            Log.d(TAG, "getValueByXmlKey $fileName 不存在")
            return ""
        }
        val map: HashMap<String, *>
        map = try {
            XmlUtils.readMapXml(FileInputStream(file))
        } catch (e: XmlPullParserException) {
            Log.d(TAG, "Error ${e.message}")
            return ""
        } catch (e: IOException) {
            Log.d(TAG, "Error ${e.message}")
            return ""
        }
        Log.i(TAG, "getValueByXmlKey ${map.keys.toTypedArray().contentToString()}, key is $key, ${map.containsKey(key)}")
        if (map != null && map.containsKey(key)) {
            val result = map[key]
            if (result != null) {
                return DesUtil.decrypt(result.toString())
            }
        }
        return ""
    }

    fun getActivationType(context: Context): String? {
        val activationState = getValueByXmlKey(context, SP_IS_ACTIVE, ACTIVATE_FILE_NAME)
        if (activationState.isNotEmpty()) {
            return when (activationState) {
                ACTIVE_TYPE_RELEASE_CODE -> "正式激活"
                ACTIVE_TYPE_TRIAL_CODE -> "试用激活"
                CAN_NOT_ACTIVE -> "无法激活"
                else -> "激活异常"
            }
        }
        val state = getValueByXmlKey(context, SP_IS_ACTIVE, PROBATION_FILE_NAME)
        if (state == PROBATION)
            return "试用期"
        return "已过期"
    }

    fun getActivationCode(context: Context): String? {
        val activationCode = getValueByXmlKey(context, SP_ACTIVE_CODE, ACTIVATE_FILE_NAME)
        if (activationCode.isNotEmpty()) {
            return activationCode
        }
        return getValueByXmlKey(context, SP_ACTIVE_CODE, PROBATION_FILE_NAME)
    }

    fun getActivationTimeStart(context: Context): String? {
        val time = getValueByXmlKey(context, SP_TRIAL_ACTIVE_START_TIME, PROBATION_FILE_NAME)
        if (time.isEmpty()) return "未获取到时间"
        val longTime: Long? = time.toLong()
        val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
        return format.format(longTime?.let { Date(it) })
    }

    fun getActivationTimeEnd(context: Context): String? {
        val activationState = getValueByXmlKey(context, SP_IS_ACTIVE, ACTIVATE_FILE_NAME)
        if (activationState.isNotEmpty()) {
            if(activationState == ACTIVE_TYPE_RELEASE_CODE){
                return "永久"
            }
        }
        val activationEndTime = getValueByXmlKey(context, SP_TRIAL_ACTIVE_END_TIME, ACTIVATE_FILE_NAME)
        if (activationEndTime.isNotEmpty()) {
            return activationEndTime.replace("  ", " ")
        }
        val time = getValueByXmlKey(context, SP_TRIAL_ACTIVE_END_TIME, PROBATION_FILE_NAME)
        if (time.isEmpty()) return "未获取到时间"
        val longTime: Long? = time.toLong()
        val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US)
        return format.format(longTime?.let { Date(it) })
    }

    @SuppressLint("PrivateApi")
    fun init(context: Context) {
        val imei = uniqueId(context, false)
        ActivationApi.getInstance().init(context, Class.forName("com.android.launcher3.Launcher"), imei, true)
    }

    interface ActivationListener {
        fun activated()

        fun activationFailed()
    }
}