package com.cartrack.cartrackble

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.bluetooth.BluetoothAdapter
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.Window
import android.view.inputmethod.InputMethodManager
import android.webkit.URLUtil
import android.widget.ArrayAdapter
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatButton
import androidx.core.app.ActivityCompat
import com.cartrack.blesdk.ctg.*
import com.cartrack.blesdk.ctg.enumerations.*
import com.cartrack.cartrackble.databinding.ActivityMainBinding
import com.cartrack.getgosample.fromJson
import com.google.android.material.snackbar.Snackbar
import com.google.gson.Gson

class MainActivity : AppCompatActivity() {

    private var test: PermissionManager? = null
    private var bleTerminal: BleTerminal? = null
    private var progressDialog: ProgressDialog? = null
    private var countryList: List<Country.Countries>? = null

    private lateinit var binding: ActivityMainBinding
    @SuppressLint("SetTextI18n")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initSpinner()

        val lastUsedTerminalId = getSharedPreferences().getString(LAST_USED_TERMINAL_ID, "")
        binding.etTerminalId.setText(lastUsedTerminalId)
        progressDialog = ProgressDialog(this)
        test = PermissionManager(this)
        test?.requestPermission()

        binding.btnRemoveKey.isEnabled = getSharedPreferences().getString(AUTH_KEY, "").isNotEmpty()

        binding.labelCurrentKey.text = "Current key: ${getSharedPreferences().getString(
            AUTH_KEY,
            "---"
        )}"

        binding.btnDisconnect.setOnClickListener {
            bleTerminal?.disconnect()
        }

        binding.btnFetchKey.setOnClickListener {
            if (!configBle()) return@setOnClickListener
            getSharedPreferences().set(LAST_USED_TERMINAL_ID, binding.etTerminalId.text.toString())
            progressDialog?.showProgress()
            getTerminal(binding.etTerminalId.text.toString())
            fetchKey()
        }
        binding.btnConnect.setOnClickListener {
            if (!configBle()) return@setOnClickListener

            getSharedPreferences().set(LAST_USED_TERMINAL_ID, binding.etTerminalId.text.toString())
            if (isEnabled()) {
                progressDialog?.showProgress()
                connect(binding.etTerminalId.text.toString())
            } else
                checkBleState()
        }

        binding.btnSetBaseUrl.setOnClickListener {
            with(binding.etSetUrl) {
                if (text.isNullOrEmpty()) {
                    error = "Please fill out"
                } else if (!URLUtil.isValidUrl(text.toString())) {
                    error = context.getString(R.string.not_valid_url)
                } else {
                    var url = text.toString()
                    if (url.last().toString() != "/") url = "$url/"
                    BleService.setApiUrl(url)
                    val imm =
                        context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                    imm.hideSoftInputFromWindow(windowToken, 0)
                    Snackbar.make(
                        binding.rootView,
                        context.getString(R.string.url_set_successfully),
                        Snackbar.LENGTH_SHORT
                    ).show()
                }
            }
        }
        binding.btnSetDefaultUrl.setOnClickListener {
            BleService.setDefaultApiUrl()
            binding.etSetUrl.setText("")
        }
        binding.btnGetVehicleState.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.GET_LOCK_STATE)
        }

        binding.btnVehicleState.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.VEHICLE_GET_CONFIG)

        }

        binding.btnChangeKey.setOnClickListener {
            if (!configBle()) return@setOnClickListener

            bleTerminal?.bleListener = bleListener
            progressDialog?.showProgress()
            bleTerminal?.randomAuthKey()
        }
        binding.btnRemoveKey.setOnClickListener {
            if (!configBle()) return@setOnClickListener
            bleTerminal?.bleListener = bleListener
            bleTerminal?.removeAuthKey()
        }

        binding.btnLock.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.LOCK)
        }
        binding.btnUnlock2.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.UNLOCK_NOKEYFOB)
        }
        binding.btnUnlock.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.UNLOCK)
        }

        binding.btnActionOne.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.HEADLIGHT)
        }
        binding.btnActionTwo.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.HORN)
        }
        binding.btnIgnitionState.setOnClickListener {
            progressDialog?.showProgress()
            bleTerminal?.sendAction(BleAction.VEHICLE_GET_STATUS)
        }
        binding.btnHasKey.setOnClickListener {
            val hasKey = bleTerminal?.hasKey() ?: false
            showSnackBar("Has Key = $hasKey")
        }
    }

    private fun initSpinner() {
        countryList = getCountry()
        val countryName: ArrayList<String> = ArrayList()
        countryList?.sortedBy { it.name }?.map {
            countryName.add(it.name.toString())
        }

        val aa = ArrayAdapter(this, android.R.layout.simple_spinner_item, countryName.toArray())
        // Set layout to use when the list of choices appear
        aa.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        // Set Adapter to Spinner
        binding.spCountry.setAdapter(aa)
        binding.spCountry.setText(countryName.find { it.contains("Singapore") }, false)
    }

    override fun onPause() {
        bleTerminal?.disconnect()
        disableAction()
        progressDialog?.hide()
        super.onPause()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            REQUEST_ON_CONNECT -> {
                if (resultCode == Activity.RESULT_OK) {
                    connect(binding.etTerminalId.text.toString())
                }
            }
        }

        super.onActivityResult(requestCode, resultCode, data)
    }

    private fun connect(terminalId: String) {
        getTerminal(terminalId)
        scanAndConnect()
        /*  if (bleTerminal?.hasKey() == true) {
              scanAndConnect()
          } else {
              fetchKeyAndConnect()
          }*/
    }

    private fun scanAndConnect() {
        bleTerminal?.scanAndConnectToPeripheral()
    }

    private fun getTerminal(terminalId: String) {
        bleTerminal = BleService.getTerminal(terminalId)
        bleTerminal?.bleListener = bleListener
    }

//    private fun fetchKeyAndConnect() {
//        bleTerminal?.prefetchAuthKey(
//            onSuccess = {
//                bleTerminal?.scanAndConnectToPeripheral()
//                progressDialog?.showProgress()
//            },
//        )
//    }

    private fun fetchKey() {
        bleTerminal?.fetchAuthKey()
    }

    private fun checkBleState() {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            showSnackBar("Please allow bluetooth permission")
            return
        }
        val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) {
            val enableBtIntent = Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE)

            startActivityForResult(enableBtIntent, REQUEST_ON_CONNECT)
        }
    }

    private fun isEnabled(): Boolean {
        val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
        return bluetoothAdapter.isEnabled
    }

    private fun enableAction() {
        binding.apply {
            btnConnect.isEnabled = false
            btnUnlock.isEnabled = true
            btnLock.isEnabled = true
            btnDisconnect.isEnabled = true
            btnActionOne.isEnabled = true
            btnActionTwo.isEnabled = true
            btnGetVehicleState.isEnabled = true
            btnUnlock2.isEnabled = true
            btnVehicleState.isEnabled = true
            btnIgnitionState.isEnabled = true
        }
    }

    private fun disableAction() {
        binding.apply {
            btnConnect.isEnabled = true
            btnUnlock.isEnabled = false
            btnLock.isEnabled = false
            btnDisconnect.isEnabled = false
            btnActionOne.isEnabled = false
            btnActionTwo.isEnabled = false
            btnGetVehicleState.isEnabled = false
            btnUnlock2.isEnabled = false
            btnVehicleState.isEnabled = false
            btnIgnitionState.isEnabled = false
        }

    }

    private fun showVehicleStatDialog(getVehicleStats: GetVehicleStats) {
        val dialog = Dialog(this@MainActivity)
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setCancelable(false)
        dialog.setContentView(R.layout.dialog_get_vehicle_state)
        getVehicleStats.apply {
            dialog.findViewById<TextView>(R.id.tvOdometer).text = odometer.toString()
            dialog.findViewById<TextView>(R.id.tvEngineHour).text = engineHours.toString()
            dialog.findViewById<TextView>(R.id.tvEngineRPM).text = engineRPM.toString()
            dialog.findViewById<TextView>(R.id.tvFuelLevel).text = fuelLevel.toString()
            dialog.findViewById<TextView>(R.id.tvHazards).text = hazardsIsOn.toString()
            dialog.findViewById<TextView>(R.id.tvIndicators).text = indicators.toString()
            dialog.findViewById<TextView>(R.id.tvBrakes).text = brakesIsActive.toString()
            dialog.findViewById<TextView>(R.id.tvHandBrake).text = handBrakeIsActive.toString()
            dialog.findViewById<TextView>(R.id.tvLights).text = lightsIsOn.toString()
            dialog.findViewById<TextView>(R.id.tvDriverDoor).text = driverDoorIsOpen.toString()
            dialog.findViewById<TextView>(R.id.tvPassengerDoor).text =
                passengerDoorIsOpen.toString()
            dialog.findViewById<TextView>(R.id.tvDriverSeatbelt).text =
                driverSeatbeltIsEngage.toString()
            dialog.findViewById<TextView>(R.id.tvPassengerSeatBelt).text =
                passengerSeatbeltIsEngage.toString()
            dialog.findViewById<TextView>(R.id.tvHorn).text = hornIsActive.toString()
            dialog.findViewById<AppCompatButton>(R.id.btn_back)
                .setOnClickListener { dialog.dismiss() }
        }
        dialog.show()
    }

    private fun showSnackBar(text: String) {
        Snackbar.make(
            binding.rootView,
            text,
            Snackbar.LENGTH_SHORT
        ).show()
    }

    private val bleListener = object : BleListener {
        override fun onTerminalConnected(terminal: BleTerminal) {
            Snackbar.make(
                binding.rootView,
                "${terminal.terminalId} Connected",
                Snackbar.LENGTH_SHORT
            ).show()

            enableAction()
            progressDialog?.dismissProgress()
        }

        @SuppressLint("SetTextI18n")
        override fun onTerminalCommandResult(
            action: BleAction,
        ) {
            showSnackBar("Success executing $action")
            binding.tvLockState.text = "Current State: ${bleTerminal?.getLockState()}"
            progressDialog?.dismissProgress()
        }

        override fun onTerminalDidGetVehicleStats(command: Byte, getVehicleStats: GetVehicleStats) {
            progressDialog?.dismissProgress()
            try {
                showVehicleStatDialog(getVehicleStats)
            } catch (e: Exception) {

                Snackbar.make(
                    binding.rootView,
                    e.message.toString(),
                    Snackbar.LENGTH_SHORT
                ).show()
            }

        }

        override fun onTerminalDidGetVehicleStatus(
            command: Byte,
            getVehicleStatus: GetVehicleStatus
        ) {
            progressDialog?.dismissProgress()
            Snackbar.make(
                binding.rootView,
                "Ignition State = " + if (getVehicleStatus.ignitionState == true) "On" else "Off",
                Snackbar.LENGTH_SHORT
            ).show()
        }


        @SuppressLint("SetTextI18n")
        override fun onTerminalDisconnected(terminal: BleTerminal) {
            Snackbar.make(
                binding.rootView,
                "${terminal.terminalId} Disconnected",
                Snackbar.LENGTH_SHORT
            ).show()
            disableAction()
            binding.tvLockState.text = "Current State: ${bleTerminal?.getLockState()}"
            progressDialog?.dismissProgress()
        }

        // WARNING: key: String?, auth key should only be for internal testing, remove it form SDK when
        // release SDK
        @SuppressLint("SetTextI18n")
        override fun onGetAuthKeySuccess(terminal: BleTerminal, s: String) {
            Snackbar.make(
                binding.rootView,
                "GetAuthKey -> Success",
                Snackbar.LENGTH_SHORT
            ).show()
            getSharedPreferences().set(AUTH_KEY, s)
            binding.labelCurrentKey.text = "Current key: ${
                getSharedPreferences().getString(
                    AUTH_KEY,
                    "---"
                )
            }"
            binding.btnRemoveKey.isEnabled =
                getSharedPreferences().getString(AUTH_KEY, "").isNotEmpty()

            progressDialog?.dismissProgress()
        }

        @SuppressLint("SetTextI18n")
        override fun onRemoveAuthKeySuccess() {
            getSharedPreferences().remove(AUTH_KEY)
            binding.labelCurrentKey.text = "Current key: ${
                getSharedPreferences().getString(
                    AUTH_KEY,
                    "---"
                )
            }"
            binding.btnRemoveKey.isEnabled =
                getSharedPreferences().getString(AUTH_KEY, "").isNotEmpty()
            showSnackBar("RemoveKey -> Success")
            progressDialog?.dismissProgress()
        }

        override fun onRandomAuthKeySuccess(result: String) {
            showSnackBar("RandomKey -> Success ")
            progressDialog?.dismissProgress()
        }

        override fun onError(errorHandler: ErrorHandler) {
            if (progressDialog?.isShowing == true) {
                progressDialog?.dismissProgress()
            }
            showSnackBar("${errorHandler.errorCode} ${errorHandler.localizedDescription}")
        }

        override fun onSignalStrength(strength: BleSignalStrength) {
            Snackbar.make(
                binding.rootView,
                strength.name,
                Snackbar.LENGTH_SHORT
            ).show()
        }
    }

    private fun getSharedPreferences(): PreferenceManager {
        return LocalPreferenceManager(
            getSharedPreferences(
                "com.cartrack.getgosample.prefs",
                Activity.MODE_PRIVATE
            )
        )
    }

    private fun getCountry(): List<Country.Countries>? {
        return Gson().fromJson<Country>(loadJSONFromAsset("country.json"))?.countries
    }

    private fun configBle(): Boolean {
        var canConfig = true
        if (binding.spVendorId.text.isNullOrEmpty()) {
            binding.spVendorId.error = "Please fill out"
            canConfig = false
        }
        if (binding.spApiKey.text.isNullOrEmpty()) {
            binding.spApiKey.error = "Please fill out"
            canConfig = false
        }
        if (binding.etTerminalId.text.isNullOrEmpty()) {
            binding.etTerminalId.error = "Please fill out"
            canConfig = false
        }
        if (!canConfig) return false
        BleService.configure(
            this,
            binding.spVendorId.text.toString(),
            binding.spApiKey.text.toString(),
            countryList?.find { it.name == binding.spCountry.text.toString() }?.countryCode.toString()
        )
        if (bleTerminal == null)
            bleTerminal = BleService.getTerminal(binding.etTerminalId.text.toString())
        return true
    }

    companion object {
        private const val REQUEST_ON_CONNECT = 101
        private const val LAST_USED_TERMINAL_ID = "lastUsedTerminalId"
        private const val AUTH_KEY = "authKey"
    }
}
