package com.doverfuelingsolutions.issp.view.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.lifecycleScope
import com.doverfuelingsolutions.issp.DFSApplication
import com.doverfuelingsolutions.issp.R
import com.doverfuelingsolutions.issp.api.SystemApi
import com.doverfuelingsolutions.issp.data.GlobalData
import com.doverfuelingsolutions.issp.databinding.FragmentSearchTypeBinding
import com.doverfuelingsolutions.issp.fusion.FusionManager
import com.doverfuelingsolutions.issp.utils.DFSToastUtil
import com.doverfuelingsolutions.issp.utils.StringUtil
import com.doverfuelingsolutions.issp.utils.log.DFSLog
import com.doverfuelingsolutions.issp.utils.sp.SPUtil
import com.doverfuelingsolutions.issp.view.LoginActivity
import com.doverfuelingsolutions.issp.view.MainActivity
import com.doverfuelingsolutions.issp.view.PreferenceActivity
import kotlinx.android.synthetic.main.layout_loading.*
import kotlinx.coroutines.*

class FragmentSelect : FragmentBasic(),
    View.OnLongClickListener,
    View.OnClickListener {

    private lateinit var binding: FragmentSearchTypeBinding
    private val viewModel: SearchTypeViewModel by viewModels()

    private var job: Job? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        if (!this::binding.isInitialized) {
            binding = DataBindingUtil.inflate(inflater, R.layout.fragment_search_type, container, false)
            binding.lifecycleOwner = this
            binding.viewModel = viewModel
            binding.handler = this
            binding.deviceNum.setOnLongClickListener(this)
        }

        return binding.root
    }

    override fun onStart() {
        super.onStart()

        handleUnsolvedOrder()
        refreshLoginToken()
    }

    override fun onStop() {
        super.onStop()

        job?.let {
            if (it.isActive) it.cancel()
        }
    }

    override fun onClick(v: View?) {
        lifecycleScope.launch {
            if (!checkFusion()) return@launch

            when (v) {
                binding.chooseNozzle -> {
                    (activity as MainActivity).setFragment(FragmentNozzle.build(FusionManager.pumpList), true)
                }
                binding.chooseOil -> {
                    (activity as MainActivity).setFragment(FragmentOrderList.build(-1), true)
                }
            }
        }
    }

    override fun onLongClick(v: View?): Boolean {
        return when (v) {
            binding.deviceNum -> {
                PreferenceActivity.startForResult(requireActivity())
                true
            }
            else -> false
        }
    }

    // TODO 当本地未处理订单无法按预期处理时（如本地锁的单，但在服务器上被其他渠道解锁了，造成解锁失败；消单同理；）
    private fun handleUnsolvedOrder() {
        GlobalScope.launch(Dispatchers.IO) {
            val lockList = SPUtil.getLockOrderList()
            val unclearedList = SPUtil.getUnclearedOrderList()
            // 解锁订单
            lockList.let { list ->
                if (list.isEmpty()) return@let

                val deferredList = list.map { item ->
                    val info = item.split("-")
                    val pumpId = info[0].toInt()
                    val transactionNo = info[1]
                    val token = info[2].toInt()
                    async {
                        FusionManager.lockOrder(pumpId, transactionNo, token, false)
                    }
                }
                val resultList = deferredList.map { item -> item.await() }
                val remainLockList = resultList.mapIndexed { index, result ->
                    val tip = "auto unlock order ${list[index]}"
                    if (result.success) {
                        DFSLog.d("$tip succeeded")
                        null
                    } else {
                        DFSLog.d("$tip failed")
                        list[index]
                    }
                }.filterNotNull()
                SPUtil.replaceLockOrderList(remainLockList)
            }
            // 消除订单
            unclearedList.let { list ->
                if (list.isEmpty()) return@let

                val deferredList = list.map { item ->
                    val info = item.split("-")
                    val pumpId = info[0].toInt()
                    val transactionNo = info[1]
                    val token = info[2].toInt()
                    async {
                        FusionManager.clearOrder(pumpId, transactionNo, token)
                    }
                }
                val resultList = deferredList.map { item -> item.await() }
                val remainLockList = resultList.mapIndexed { index, result ->
                    val tip = "auto clear order ${list[index]}"
                    if (result.success) {
                        DFSLog.d("$tip succeeded")
                        null
                    } else {
                        DFSLog.d("$tip failed")
                        list[index]
                    }
                }.filterNotNull()
                SPUtil.replaceUnclearedOrderList(remainLockList)
            }
            // 删除过期云订单
            SPUtil.removeExpiredWayneOrder()
        }
    }

    private fun refreshLoginToken() {
        // 登录有效时长两小时，为了避免在操作过程出现接口验证失败
        job = lifecycleScope.launch {
            // 8min 余留，避免边缘时刻进入流程
            val expireMoment = GlobalData.accessTokenExpire.get()
            val delayTime = expireMoment - 480000 - System.currentTimeMillis()
            if (delayTime > 0) {
                delay(delayTime)
            }
            val result = SystemApi.login(GlobalData.accountName.get(), GlobalData.password.get())
            if (result.success) {
                DFSLog.d("loginToken refresh succeeded")
                // 处理持续停留
                refreshLoginToken()
            } else {
                DFSLog.d("loginToken refresh failed: ${result.message}")
                GlobalData.isLogin = false
                val msg = StringUtil.get(R.string.fail_refresh_login)
                DFSToastUtil.fail(msg)
                // 刷新失败返回登录界面
                (activity as MainActivity).finish()
                LoginActivity.start(
                    requireContext(),
                    bundleOf(
                        Pair(LoginActivity.autoLogin, false),
                        Pair(LoginActivity.loginMessage, msg),
                    )
                )
            }
        }
    }

    private suspend fun checkFusion(): Boolean {
        if (!FusionManager.isLogin) {
            val dialog = loading(R.string.in_login_fusion)
            val success = FusionManager.loginToFusion()
            dialog.dismiss()
            if (!success) {
                DFSToastUtil.fail(R.string.fusion_login_failed)
                return false
            }
        }

        if (!FusionManager.isFetchPumpInfo) {
            val dialog = loading(R.string.in_get_fuel)
            val result = FusionManager.getPumpInfo()
            dialog.dismiss()
            if (!result.success) {
                DFSToastUtil.fail(R.string.get_fuel_failed)
                return false
            }
        }

        return true
    }

    class SearchTypeViewModel : ViewModel() {
        val deviceNum = MutableLiveData(GlobalData.serialNumber.get())
        val version: MutableLiveData<String> by lazy {
            val pm = DFSApplication.instance.applicationContext.packageManager
            val info = pm.getPackageInfo(
                DFSApplication.instance.applicationContext.packageName,
                android.content.pm.PackageManager.GET_ACTIVITIES
            )
            MutableLiveData(info.versionName)
        }
    }
}