package es.verdnatura.presentation.view.feature.delivery.fragments

import android.content.Context
import android.content.Intent
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.activity.OnBackPressedDispatcher
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import es.verdnatura.R
import es.verdnatura.databinding.FragmentExpeditionLoadunloadDeliveryBinding
import es.verdnatura.db.DeliveryDatabase
import es.verdnatura.domain.toDateString
import es.verdnatura.domain.toast
import es.verdnatura.presentation.base.BaseFragment
import es.verdnatura.presentation.base.database
import es.verdnatura.presentation.common.OnBackPressedListener
import es.verdnatura.presentation.common.OnOptionsSelectedListener
import es.verdnatura.presentation.common.ToolBarAdapterTooltip
import es.verdnatura.presentation.view.component.CustomDialog
import es.verdnatura.presentation.view.feature.delivery.activity.SignedActivity
import es.verdnatura.presentation.view.feature.delivery.adapters.ExpeditionLoadUnloadAdapter
import es.verdnatura.presentation.view.feature.delivery.model.ClientTicketSalix
import es.verdnatura.presentation.view.feature.delivery.model.ExpeditionInfoLoadUnload
import es.verdnatura.presentation.view.feature.delivery.model.ExpeditionInfoPending
import es.verdnatura.presentation.view.feature.delivery.model.ExpeditionSalix
import es.verdnatura.presentation.view.feature.delivery.model.RouteLoaded
import es.verdnatura.presentation.view.feature.delivery.viewmodels.DeliveryViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.util.Date

class LoadUnloadFragment(
    private var title: String = "",
    private var state: String = "",
    private var entryPoint: String,
    private var clientTicketList: ArrayList<ClientTicketSalix>?

) : BaseFragment<FragmentExpeditionLoadunloadDeliveryBinding, DeliveryViewModel>(
    DeliveryViewModel::class
), OnBackPressedListener {

    private var adapter: ExpeditionLoadUnloadAdapter? = null
    private var originalItem: Int = 0
    private lateinit var myList: MutableList<ExpeditionInfoLoadUnload>
    private var counterCalls = 0
    private var counterResponse = 0
    private var route = 0
    private var addressFk = 0
    private lateinit var db: DeliveryDatabase
    private lateinit var backDispatcher: OnBackPressedDispatcher

    companion object {
        var scanned = false
        fun newInstance(
            title: String,
            state: String,
            entryPoint: String,
            clientTicketList: ArrayList<ClientTicketSalix>? = null
        ) = LoadUnloadFragment(title, state, entryPoint, clientTicketList)

        fun scanning(scan: Boolean) {
            scanned = scan
        }
    }

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

        requireActivity().onBackPressedDispatcher.addCallback(
            viewLifecycleOwner,
            object : OnBackPressedCallback(true) {
                override fun handleOnBackPressed() {
                    if (!onBackPressedHandled()) {
                        isEnabled = false
                        requireActivity().onBackPressedDispatcher
                    }
                }
            })
    }

    override fun getLayoutId(): Int = R.layout.fragment_expedition_loadunload_delivery

    override fun init() {
        try {
            route = JSONObject(entryPoint).get("route").toString().toInt()
            addressFk = JSONObject(entryPoint).get("address").toString().toInt()
        } catch (ex: Exception) {
            ex.message.toString().toast(requireContext())
        }
        setEvents()
        setToolBar()
        setSwitchButon()
        binding.scanInput.requestFocus()
        viewModel.getExpeditionFromRoute(route)
        super.init()
    }

    override fun onAttach(context: Context) {
        super.onAttach(context)
        db = database(requireContext().applicationContext)
    }

    private fun setToolBar() {
        ma.hideBottomNavigation(View.GONE)
        binding.mainToolbar.toolbarTitle.visibility = View.VISIBLE
        binding.mainToolbar.toolbarSubtitle.visibility = View.VISIBLE
        binding.mainToolbar.toolbarSubtitle.setTextColor(requireContext().getColor((R.color.verdnatura_pumpkin_orange)))
        binding.mainToolbar.toolbarIcons.visibility = View.VISIBLE
        binding.mainToolbar.switchButton.visibility = if (state != "DELIVERED") {
            View.VISIBLE
        } else {
            View.GONE
        }
        binding.mainToolbar.toolbarTitle.text = title

        val listIcons: ArrayList<ImageView> = ArrayList()
        val iconConfirm = ImageView(context)
        val iconSign = ImageView(context)

        iconConfirm.setImageResource(R.drawable.ic_confirm)
        iconSign.setImageResource(R.drawable.ic_sign)

        iconConfirm.tooltipText = getTooltip(R.drawable.ic_confirm)
        listIcons.add(
            if (state == "DELIVERED") {
                iconSign
            } else {
                iconConfirm
            }
        )

        binding.mainToolbar.toolbarIcons.adapter =
            ToolBarAdapterTooltip(listIcons, object : OnOptionsSelectedListener {

                override fun onOptionsItemSelected(item: Drawable) {
                    try {

                        when (item) {
                            iconConfirm.drawable -> {
                                saveLoaded()
                                setExpeditionsState(myList, state)
                            }

                            iconSign.drawable -> {
                                setExpeditionsState(myList, state)
                            }
                        }
                    } catch (ex: Exception) {
                        getString(R.string.errorNotData).toast(requireContext())
                    }

                }

            })

        binding.mainToolbar.toolbarIcons.layoutManager =
            LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false)
        binding.mainToolbar.toolbarIcons.visibility = View.VISIBLE
    }

    private fun saveLoaded() {
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                db.routesDao().insertLoaded(RouteLoaded(route.toLong(), toDateString(Date())))
            }
        }

    }

    private fun setExpeditionsState(list: MutableList<ExpeditionInfoLoadUnload>, state: String) {
        scanning(false)
        val mlist = mutableListOf<ExpeditionSalix>()
        for (l in list) {
            mlist.add(
                ExpeditionSalix(
                    expeditionFk = l.id, stateCode = if (l.code != state && l.code != "FOUND") {
                        "LOST"
                    } else {
                        l.code
                    }, isScanned = l.isScanned
                )
            )
        }
        val expeditionBack = hashMapOf("expeditions" to mlist as List<ExpeditionSalix>)
        if (list.any { it.code == state }) {
            if (list.filter { it.code == state }.size == list.size) {
                viewModel.expeditionStateAddSalix(expeditionBack)
                counterCalls = 1
            } else {
                val alertDialog = android.app.AlertDialog.Builder(requireContext()).create()
                alertDialog.setTitle(getString(R.string.info))
                alertDialog.setMessage(getString(R.string.expeditionTotal))
                alertDialog.setButton(
                    android.app.AlertDialog.BUTTON_NEUTRAL, getString(R.string.save)
                ) { _, _ ->
                    counterCalls = 1
                    viewModel.expeditionStateAddSalix(expeditionBack)
                }
                alertDialog.setButton(
                    android.app.AlertDialog.BUTTON_POSITIVE, getString(R.string.ordenar)
                ) { _, _ ->
                    createList(list.sortedByDescending { it.code } as MutableList<ExpeditionInfoLoadUnload>)
                }
                alertDialog.show()
            }
        } else {
            val alertDialog = android.app.AlertDialog.Builder(requireContext()).create()
            alertDialog.setTitle(getString(R.string.info))
            alertDialog.setMessage(getString(R.string.scanForSign))
            alertDialog.setButton(
                android.app.AlertDialog.BUTTON_NEUTRAL, getString(R.string.accept)
            ) { _, _ ->
                alertDialog.dismiss()
            }
            alertDialog.show()

        }

    }

    private fun openSignActivity() {
        try {
            val intent = Intent(requireContext(), SignedActivity::class.java)
            intent.putExtra(
                "clientTicketList", clientTicketList!!.first()
            )
            intent.putExtra("objectSigned", "ticket") //cmr
            startActivity(intent)
            ma.onMyBackPressed()
        } catch (ex: Exception) {
            ma.messageWithSound(
                message = getString(R.string.errorSignActivity),
                isError = true,
                isToasted = true,
                isPlayed = true
            )
        }

    }

    private fun setEvents() {

        binding.mainToolbar.backButton.setOnClickListener {
            ma.onMyBackPressed()
        }

        binding.scanInput.setOnEditorActionListener { v, actionId, event ->
            if (actionId == EditorInfo.IME_ACTION_SEARCH || actionId == EditorInfo.IME_ACTION_DONE || actionId == 0 || actionId == EditorInfo.IME_ACTION_NEXT) {

                if (!binding.scanInput.text.isNullOrEmpty()) {
                    val isScanned =
                        event != null && event.action == KeyEvent.ACTION_DOWN && event.keyCode == KeyEvent.KEYCODE_ENTER
                    try {
                        markExpedition(
                            binding.scanInput.text.toString().toInt(),
                            if (!binding.mainToolbar.switchButton.isChecked) {
                                state
                            } else {
                                "FOUND"
                            },
                            isScanned = if (isScanned) 1 else 0
                        )
                        if (state != "DELIVERED") {

                            binding.mainToolbar.toolbarTitle.text =
                                if (!binding.mainToolbar.switchButton.isChecked) {
                                    getString(R.string.loading)
                                } else {
                                    getString(R.string.unloading)
                                }
                        }

                    } catch (ex: Exception) {
                        getString(R.string.errorExpedition).toast(context, Toast.LENGTH_SHORT)
                    }
                    binding.scanInput.setText("")
                }

                return@setOnEditorActionListener true
            }
            false
        }

        binding.scanInput.requestFocus()
    }

    private fun markExpedition(expedNumber: Int, state: String, isScanned: Int) {

        var found = false

        if (myList.filter { it.id == expedNumber }.any { it.code == state }) {
            ma.messageWithSound(getString(R.string.expeditionMarked), null, true)
        } else {
            for (exped in myList) {
                if (exped.id == expedNumber) {
                    found = true
                    exped.code = state
                    exped.isScanned = isScanned
                    break
                }
            }
            if (found) {
                ma.messageWithSound(
                    message = "",
                    isError = false,
                    isPlayed = true,
                    isToasted = false
                )
                scanning(true)
            } else {
                ma.messageWithSound("", isError = true, isPlayed = true, isToasted = null)
            }
        }

        if (binding.mainToolbar.switchButton.isChecked) {
            counterCalls = 1
            val pendingExpeditionSend = myList.map { l ->
                ExpeditionSalix(
                    expeditionFk = l.id, stateCode = l.code, isScanned = l.isScanned
                )
            }
            viewModel.expeditionStateAddSalix(hashMapOf("expeditions" to pendingExpeditionSend.filter { it.stateCode == state }))
        } else {
            updateCount(myList, state)
        }
    }

    override fun observeViewModel() {
        with(viewModel) {
            expeditionInfoLoadUnloadList.observe(viewLifecycleOwner) {
                createList(it.list as MutableList<ExpeditionInfoLoadUnload>)
            }
            routeInfoList.observe(viewLifecycleOwner) {
                if (it.list.isNotEmpty()) {
                    binding.mainToolbar.toolbarIcons.visibility = View.VISIBLE
                    binding.mainToolbar.switchButton.visibility = View.VISIBLE
                } else {
                    binding.scanInput.setText("")
                    binding.mainToolbar.toolbarIcons.visibility = View.GONE
                    binding.mainToolbar.switchButton.visibility = View.GONE
                }
            }
            responseStateAdd.observe(viewLifecycleOwner) {
                if (it) {
                    counterResponse += 1
                    if (counterResponse == counterCalls) {
                        if (!binding.mainToolbar.switchButton.isChecked) {
                            if (state == "DELIVERED") {
                                openSignActivity()
                            } else {
                                ma.onMyBackPressed()
                            }
                        } else {
                            binding.mainToolbar.switchButton.isChecked = false
                        }
                        counterResponse = 0
                        counterCalls = 0
                    }
                } else {
                    openSignActivity()
                }

            }
            responseStateList.observe(viewLifecycleOwner) {
                savePendingExpeditions()
                openSignActivity()
            }

            responseLoadList.observe(viewLifecycleOwner) {
                createList(mutableListOf(), true)
            }
        }
    }

    private fun savePendingExpeditions() {
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {

                val myListPending = myList.map { item ->
                    ExpeditionInfoPending(
                        id = item.id,
                        ticketFk = item.ticketFk,
                        routeFk = item.routeFk,
                        addressFk = item.addressFk,
                        itemPackingTypeConcat = item.itemPackingTypeConcat,
                        city = item.city,
                        street = item.street,
                        code = if (item.code == "DELIVERED" || item.code == "ON DELIVERY") {
                            item.code
                        } else {
                            "LOST"
                        },
                        nickname = item.nickname,
                        postalCode = item.postalCode
                    )
                } as MutableList<ExpeditionInfoPending>

                db.expedicionDao().insertPending(myListPending)

            }
        }

    }

    private fun setSwitchButon() {
        binding.mainToolbar.switchButton.tooltipText = getString(R.string.expeditionMarkLost)
        binding.mainToolbar.switchButton.setOnCheckedChangeListener { _, isChecked ->
            binding.mainToolbar.switchButton.tooltipText =
                if (isChecked) getString(R.string.expeditionMarkFound) else getString(R.string.expeditionMarkLost)


            binding.mainToolbar.toolbarTitle.text = if (isChecked) {
                getString(R.string.unloading)
            } else {
                getString(R.string.loading)
            }
            getString(R.string.unloading)

        }

    }

    private fun createList(list: MutableList<ExpeditionInfoLoadUnload>, getSaved: Boolean = false) {

        lifecycleScope.launch {
            withContext(Dispatchers.IO) {

                if (getSaved) {
                    myList = db.expedicionDao().getAllPending(route)
                    if (myList.isEmpty()) {
                        myList = db.expedicionDao().getAll(route)
                    }

                } else {
                    db.expedicionDao().insert(list)
                    myList = list
                }

            }
            if (addressFk != 0) {
                myList =
                    myList.filter { it.addressFk == addressFk } as MutableList<ExpeditionInfoLoadUnload>
            } else {
                myList.filter {
                    it.routeFk == route
                }
            }
            adapter = ExpeditionLoadUnloadAdapter(myList)
            binding.expeditionloadunloadRecyclerview.adapter = adapter
            binding.expeditionloadunloadRecyclerview.layoutManager =
                LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
            binding.mainToolbar.toolbarSubtitle.text = getString(
                R.string.summaryCount, myList.filter { it.code == state }.size, myList.size
            )

            setListPosition(myList)
        }

    }

    private fun updateExpeditionTable(list: List<ExpeditionInfoLoadUnload>) {
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                db.expedicionDao().insert(list.filter { it.routeFk == route }
                    .filter { it.addressFk == addressFk } as MutableList<ExpeditionInfoLoadUnload>)

            }
        }

    }

    private fun getExpeditionTable(myRoute: Int) {
        lifecycleScope.launch {
            withContext(Dispatchers.IO) {
                myList = db.expedicionDao().getAll(myRoute)
            }

        }
    }

    private fun setListPosition(list: MutableList<ExpeditionInfoLoadUnload>) {
        for (i in list.indices) {
            if (list[i].code != state) {
                binding.expeditionloadunloadRecyclerview.scrollToPosition(i)
                break
            }
        }
    }

    private fun updateCount(list: MutableList<ExpeditionInfoLoadUnload>, state: String) {

        val countMarked = list.filter { it.code == state }.size
        binding.mainToolbar.toolbarSubtitle.text =
            getString(R.string.summaryCount, countMarked, list.size)

        if (countMarked == list.size) {
            setExpeditionsState(list, state)
        }
        adapter!!.notifyDataSetChanged()
    }

    override fun onBackPressedHandled(): Boolean {

        if (scanned) {
            var customDialog = CustomDialog(requireContext())
            customDialog.setTitle(getString(R.string.packagesNotScanned))
                .setDescription(getString(R.string.savePackages))
                .setOkButton(getString(R.string.yes)) {
                    customDialog.dismiss()
                }.setKoButton(getString(R.string.no)) {
                    customDialog.dismiss()
                    ma.onMyBackPressed()
                }.show()

        } else {
            return false
        }
        return true
    }
}