package com.doverfuelingsolutions.issp.view

import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.View
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.lifecycleScope
import com.doverfuelingsolutions.issp.R
import com.doverfuelingsolutions.issp.api.SystemApi
import com.doverfuelingsolutions.issp.data.GlobalData
import com.doverfuelingsolutions.issp.databinding.ActivityMainBinding
import com.doverfuelingsolutions.issp.fusion.FusionManager
import com.doverfuelingsolutions.issp.fusion.FusionStatus
import com.doverfuelingsolutions.issp.fusion.callback.OnFusionStatus
import com.doverfuelingsolutions.issp.utils.DFSToastUtil
import com.doverfuelingsolutions.issp.utils.WindowUtil
import com.doverfuelingsolutions.issp.utils.log.DFSLog
import com.doverfuelingsolutions.issp.utils.sp.SPKeys
import com.doverfuelingsolutions.issp.utils.sp.SPUtil
import com.doverfuelingsolutions.issp.view.fragment.FragmentNozzle
import com.doverfuelingsolutions.issp.view.fragment.FragmentReconnect
import com.doverfuelingsolutions.issp.view.fragment.FragmentSelect
import com.doverfuelingsolutions.issp.view.fragment.router.FragmentRouter
import com.doverfuelingsolutions.issp.view.fragment.router.OnRouteChangeListener
import com.doverfuelingsolutions.issp.view.util.LoadingDialogBuilder
import com.doverfuelingsolutions.issp.view.util.LoginTokenRefresher
import com.wayne.www.waynelib.fdc.FdcClient
import com.youth.banner.adapter.BannerImageAdapter
import com.youth.banner.holder.BannerImageHolder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import java.io.File
import java.util.*

class MainActivity : AppCompatActivity(),
    View.OnClickListener,
    View.OnLongClickListener,
    OnFusionStatus,
    OnRouteChangeListener {

    companion object {
        fun start(context: Context) {
            Intent(context, MainActivity::class.java).let { context.startActivity(it) }
        }
    }

    private val binding: ActivityMainBinding by lazy {
        DataBindingUtil.setContentView(this, R.layout.activity_main)
    }
    private val mainViewModel: MainViewModel by viewModels()
    val fragmentRouter: FragmentRouter by lazy { FragmentRouter(this, R.id.fragmentBox) }

    private var dialogFusionLinking: AlertDialog? = null
    private var isBlockBackPress = false

    private val mLoginTokenRefresher = LoginTokenRefresher()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding.lifecycleOwner = this
        binding.mainViewModel = mainViewModel
        binding.handler = this
        binding.clock.setOnLongClickListener(this)

        supportActionBar?.hide()
        initView()
        initBanner()

        FusionManager.onFusionStatus = this
        lifecycle.addObserver(FusionManager)

        fragmentRouter.setFragmentToolbar(binding.fragmentToolbar)
        fragmentRouter.setOnRouteChangeListener(this)

        mLoginTokenRefresher.start(this)
    }

    override fun onResume() {
        super.onResume()
        WindowUtil.setFullscreen(this)
    }

    override fun onDestroy() {
        super.onDestroy()

        dialogFusionLinking?.dismiss()
        dialogFusionLinking = null
        fragmentRouter.stopFragmentToolbarTimer()
        FusionManager.onFusionStatus = null
        mLoginTokenRefresher.stop()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        lifecycleScope.launch {
            when (requestCode) {
                PreferenceActivity.codeRequestResult -> {
                    data?.let {
                        val isMiddleModified = it.getBooleanExtra(PreferenceActivity.isMiddleModified, false)
                        val isFuelModified = it.getBooleanExtra(PreferenceActivity.isFuelModified, false)
                        val isChooseOrderTypeModified = it.getBooleanExtra(PreferenceActivity.isChooseOrderTypeModified, false)

                        if (isMiddleModified || FusionManager.stateFusion != FdcClient.FdcClientState.Connected) {
                            setFusionLinkingLoading()
                            FusionManager.restart(true)
                            return@let
                        } else if (isFuelModified && FusionManager.stateFusion == FdcClient.FdcClientState.Connected) {
                            val dialog = LoadingDialogBuilder(this@MainActivity)
                                .setLoadingText(R.string.in_get_fuel)
                                .show()
                            val result = FusionManager.getPumpInfo()
                            dialog.dismiss()
                            if (result.success) {
                                DFSToastUtil.success(R.string.get_fuel_success)
                            } else {
                                DFSToastUtil.fail(R.string.get_fuel_failed)
                                onFusionStatus(FusionStatus.ConnectedWithoutInfo)
                                return@let
                            }
                        }

                        if (isChooseOrderTypeModified) {
                            initFragmentEntry()
                        }
                    }
                }
            }
        }
    }

    override fun onBackPressed() {
        if (!isBlockBackPress) super.onBackPressed()
    }

    override fun onClick(v: View?) {
        when (v) {
            binding.stationLogo,
            binding.stationName -> {
                DFSLog.i("refresh station info")
                lifecycleScope.launch {
                    val resultPhone = SystemApi.sessionInfo()
                    if (resultPhone.success && resultPhone.data != null) {
                        GlobalData.stationTel.set(resultPhone.data.phoneNumber)
                        GlobalData.businessName.set(resultPhone.data.currentbuName)
                    }

                    val resultLogo = SystemApi.stationLogo()
                    if (resultLogo.success && !resultLogo.data.isNullOrBlank()) {
                        GlobalData.stationLogoFileName.set(resultLogo.data)
                    }

                    initView()
                    DFSToastUtil.success(R.string.refresh_success)
                }
            }
        }
    }

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

    override fun onFusionStatus(status: FusionStatus) {
        DFSLog.i("Fusion output status: ${status.name.toLowerCase(Locale.CHINESE)}")
        lifecycleScope.launch {
            dialogFusionLinking?.dismiss()
            when (status) {
                FusionStatus.Connecting -> {
                    setFusionLinkingLoading()
                }
                FusionStatus.Connected -> {
                    DFSToastUtil.success(R.string.connect_fusion_success)
                    initFragmentEntry()
                }
                FusionStatus.ConnectedWithoutInfo -> {
                    DFSToastUtil.fail(R.string.get_fuel_failed)
                    fragmentRouter.push(FragmentReconnect.build {
                        DFSToastUtil.success(R.string.get_fuel_success)
                        initFragmentEntry()
                    })
                }
                FusionStatus.Disconnected -> {
                    // Disconnected reason
                    // 1. Network problem.
                    // 2. Communication exception and failed retry.
                    DFSToastUtil.fail(R.string.disconnect_fusion)
                    fragmentRouter.push(FragmentReconnect.build {
                        setFusionLinkingLoading()
                    })
                }
            }
        }
    }

    override fun onRouteForward() {
        mLoginTokenRefresher.stop()
    }

    override fun onRouteBackward(isBottom: Boolean) {
        if (isBottom) {
            mLoginTokenRefresher.start(this)
            handleUnsolvedOrder()
        }
    }

    fun blockBackPress(isBlock: Boolean) {
        isBlockBackPress = isBlock
    }

    private fun initView() {
        mainViewModel.stationName.value = GlobalData.businessName.get()
        if (GlobalData.stationLogoFileName.get().isNotEmpty()) {
            binding.stationLogo.setImageURI(Uri.fromFile(File(filesDir, GlobalData.stationLogoFileName.get())))
        }
    }

    private fun initBanner() {
        binding.banner.run {
            addBannerLifecycleObserver(this@MainActivity)
            scrollTime = 500
            adapter =
                object : BannerImageAdapter<Int>(listOf(R.mipmap.banner_1, R.mipmap.banner_2)) {
                    override fun onBindView(
                        holder: BannerImageHolder,
                        data: Int,
                        position: Int,
                        size: Int
                    ) {
                        holder.imageView.setImageResource(data)
                    }
                }
        }
    }

    private fun setFusionLinkingLoading() {
        // Don't dismiss dialog, just show & hide for reuse.
        dialogFusionLinking?.dismiss()
        dialogFusionLinking = LoadingDialogBuilder(this@MainActivity)
            .setTitle(R.string.fusion_in_connect)
            .setLoadingText(R.string.reconnect_fusion_tip)
            .setCancelable(true)
            .show()
        dialogFusionLinking?.window?.let { WindowUtil.setFullscreen(it) }
    }

    private fun initFragmentEntry() {
        fragmentRouter.setHomeFragment(
            if (SPUtil.getString(SPKeys.ORDER_CHOOSE) == "nozzle") {
                FragmentNozzle.build(FusionManager.pumpList)
            } else {
                FragmentSelect()
            }
        )
    }

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

    class MainViewModel : ViewModel() {
        val stationName = MutableLiveData("")
    }
}