package com.doverfuelingsolutions.issp.view.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
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.log.DFSLog
import com.doverfuelingsolutions.issp.utils.sp.SPUtil
import com.doverfuelingsolutions.issp.view.MainActivity
import kotlinx.coroutines.*

class FragmentSelect : Fragment(),
    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
        }
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        handleUnsolvedOrder()
    }

    override fun onStart() {
        super.onStart()

        refreshLoginToken()
    }

    override fun onStop() {
        super.onStop()

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

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

    // TODO 当本地未处理订单无法按预期处理时（如本地锁的单，但在服务器上被其他渠道解锁了，造成解锁失败；消单同理；）
    /* 未处理的订单 */
    private fun handleUnsolvedOrder() {
        GlobalScope.launch(Dispatchers.IO) {
            val lockList = SPUtil.getLockOrderList()
            val unclearedList = SPUtil.getUnclearedOrderList()
            DFSLog.i("try handle orders triggered by this device: locked ${lockList.size}, uncleared ${unclearedList.size}")
            // 解锁订单
            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 = "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 = "clear order「${list[index]}」"
                    if (result.success) {
                        DFSLog.d("$tip succeeded")
                        null
                    } else {
                        DFSLog.d("$tip failed")
                        list[index]
                    }
                }.filterNotNull()
                SPUtil.replaceUnclearedOrderList(remainLockList)
            }
        }
    }

    /* 刷新登录状态 */
    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}")
                // 刷新失败返回登录界面
                (activity as MainActivity).backToLogin()
            }
        }
    }

    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)
        }
    }
}