package com.nxp.vizncompanionapp.activities

import android.Manifest
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModelProviders
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothProfile
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.location.LocationManager
import android.net.Uri
import android.net.wifi.ScanResult
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.Settings
import android.support.v4.app.ActivityCompat
import android.util.Log
import android.view.MenuItem
import com.nxp.vizncompanionapp.R
import com.nxp.vizncompanionapp.utility.AppConstant
import com.nxp.vizncompanionapp.utility.DisplayNotifications
import com.nxp.vizncompanionapp.utility.PreferencesHelper
import kotlinx.android.synthetic.main.activity_device_listing.*
import android.support.v7.widget.LinearLayoutManager
import android.view.Menu
import android.view.View
import android.widget.Toast
import com.nxp.vizncompanionapp.adapters.WifiListAdapter
import com.nxp.vizncompanionapp.viewModel.BLEViewModel
import com.nxp.vizncompanionapp.viewModel.DeviceViewModel
import com.nxp.vizncompanionapp.viewModel.WiFiViewModel
import com.squareup.otto.Subscribe
import com.thedamfr.android.BleEventAdapter.BleEventBus
import com.thedamfr.android.BleEventAdapter.events.CharacteristicWriteEvent
import com.thedamfr.android.BleEventAdapter.events.GattConnectionStateChangedEvent
import com.thedamfr.android.BleEventAdapter.events.ServiceDiscoveredEvent
import com.thedamfr.android.BleEventAdapter.service.gatt.GattConnectionState
import kotlinx.android.synthetic.main.content_wifi_listing.*
import org.json.JSONObject
import java.util.*


class WifiListingActivity : AppCompatActivity() {

    private val REQUEST_LOCATION = 1
    private var mDisplayNotifications: DisplayNotifications = DisplayNotifications()
    /**
     * Permissions needed for location service
     */
    private val PERMISSIONS_LOCATION = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION)
    var prefeernce: PreferencesHelper? = null
    private var mWiFiViewModel: WiFiViewModel? = null
    private var mDeviceViewModel: DeviceViewModel? = null
    private var mBLEViewModel: BLEViewModel? = null
    var adapter : WifiListAdapter? = null
    var ipAddress : String? = null
    var ssid: String = ""
    private var bluetoothDevice: BluetoothDevice? = null
    var type: String? = null
    private var bluetoothGatt: BluetoothGatt? = null
    private var isGUIDWritten: Boolean = false
    var json = JSONObject()
    var isCreate: Boolean = false
    var isGoToSeetings : Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_wifi_listing)
        setSupportActionBar(toolbar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        this.prefeernce = PreferencesHelper(this)

        ipAddress = intent.getStringExtra("ipAddress")
        type = intent.getStringExtra("action")
        if(type == "ble_mode") {
            bluetoothDevice = intent.extras.getParcelable("device")
            Log.e("TAG device", bluetoothDevice?.name)
        }
        isCreate = true

        adapter = WifiListAdapter(this)
        rvWifiList.adapter = adapter
        rvWifiList.layoutManager = LinearLayoutManager(this)

        mWiFiViewModel = ViewModelProviders.of(this).get(WiFiViewModel::class.java)

        mDeviceViewModel = ViewModelProviders.of(this).get(DeviceViewModel::class.java)

        mBLEViewModel = ViewModelProviders.of(this).get(BLEViewModel::class.java)

        mWiFiViewModel?.getAllwifis()?.observe(this, Observer { listScanResults ->
            // Update the cached copy of the words in the adapter.
            adapter?.setDevices(listScanResults)
        })


        onClickListener()
    }

    override fun onStart() {
        super.onStart()
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            if (prefeernce?.loadSavedStringPreferences(AppConstant.SHARED_KEY_NEVER_ASK_AGAIN_LOCATION_PERMISSION) == "") {
                setupLocationPermission()
            } else {
                mDisplayNotifications?.displayErrorDialog(this, getString(R.string.permissions_not_granted),getString(R.string.settings),getString(R.string.cancel))
            }
        } else {
            statusCheck()
        }
    }

    fun gotoDeviceListingScreen(){
        intent = Intent(this, DeviceListingActivity::class.java)
        intent.putExtra("action","broadcast")
        startActivity(intent)
        overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left)
        finish()
    }

    private fun onClickListener() {
        adapter?.setOnItemClickListener(object : WifiListAdapter.MyClickListener {
            override fun onItemClick(position: Int, v: View, mDeviceList: List<ScanResult>?) {
                ssid = mDeviceList?.get(position)?.SSID!!
                if(type == "ap_mode" || type == "update_mode") {
                    if (!mDeviceList?.get(position)?.capabilities?.contains("WPA2")!! && !mDeviceList?.get(position)?.capabilities?.contains("WPA")!!) {
                        SendCredtoDevice(this@WifiListingActivity, ipAddress!!, mDeviceList?.get(position)?.SSID, "", type)
                    } else {
                        mDisplayNotifications?.displayWiFiPasswordDialog(this@WifiListingActivity, mDeviceList?.get(position)?.SSID, ipAddress!!, "wifi", type)
                    }
                } else {
                    if (!mDeviceList?.get(position)?.capabilities?.contains("WPA2")!! && !mDeviceList?.get(position)?.capabilities?.contains("WPA")!!) {
                        SendCredtoDevice(this@WifiListingActivity, "", mDeviceList?.get(position)?.SSID, "",type)
                    } else {
                        mDisplayNotifications?.displayWiFiPasswordDialog(this@WifiListingActivity, mDeviceList?.get(position)?.SSID, "", "wifi",type)
                    }
                }
            }
        })
    }

    fun SendCredtoDevice(context: Context, ipAddress: String, ssid: String, password: String, type: String?){
        if(type == "ap_mode" || type == "update_mode") {
            mDeviceViewModel?.sendWiFiCredentials(context, ipAddress, ssid, password,type)
        } else {
            json.put("SSID",ssid)
            json.put("Password",password)
            if(!mBLEViewModel?.checkForBLE(this)!!){
                Toast.makeText(this,getString(R.string.bluetooth_not_support_msg), Toast.LENGTH_SHORT).show()
            } else {
                mBLEViewModel?.checkBLEState(this)
            }

        }
    }

    fun connectDeviceWithBt(){
        if(bluetoothDevice != null) {
            mBLEViewModel?.connectToDevice(this, bluetoothDevice!!)
        }
        else{

        }
    }

    fun turnOnBLERequest(){
        mBLEViewModel?.turnOnBLE()
        mDisplayNotifications?.fetchData(this)
        Handler(Looper.getMainLooper()).postDelayed({
            mDisplayNotifications?.dismissDialog()
            if(bluetoothDevice != null) {
                mBLEViewModel?.connectToDevice(this, bluetoothDevice!!)
            }
            else{
            }
        }, 1000)
    }

    /**
     * Check the device version for permission
     */
    private fun setupLocationPermission() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            // Location permissions have not been granted.
            requestLocationPermissions()
        } else {
            statusCheck()
        }
    }

    /**
     * Requests the Location permissions.
     * If the permission has been denied previously, a SnackBar will prompt the user to grant the
     * permission, otherwise it is requested directly.
     */
    fun requestLocationPermissions() {
        // BEGIN_INCLUDE(location_permission_request)
        ActivityCompat.requestPermissions(this, PERMISSIONS_LOCATION, REQUEST_LOCATION)
        // END_INCLUDE(location_permission_request)
    }

    /**
     * Callback received when a permissions request has been completed.
     */
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        if (requestCode == REQUEST_LOCATION) {
            // We have requested multiple permissions for location, so all of them need to be
            val hasSth = grantResults.isNotEmpty()
            if (hasSth) {
                // checked.
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    prefeernce?.savePreferences(AppConstant.SHARED_KEY_NEVER_ASK_AGAIN_LOCATION_PERMISSION,"")
                    statusCheck()
                } else if (grantResults[0] == PackageManager.PERMISSION_DENIED) {
                    if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                                    Manifest.permission.ACCESS_FINE_LOCATION) || ActivityCompat.shouldShowRequestPermissionRationale(this,
                                    Manifest.permission.ACCESS_COARSE_LOCATION)) {
                        mDisplayNotifications?.displayErrorDialog(this,getString(R.string.permission_location_access),getString(R.string.ok),getString(R.string.cancel))
                    } else {
                        prefeernce?.savePreferences(AppConstant.SHARED_KEY_NEVER_ASK_AGAIN_LOCATION_PERMISSION,"check")
                        mDisplayNotifications?.displayErrorDialog(this,getString(R.string.permissions_not_granted),getString(R.string.settings),getString(R.string.cancel))
                    }
                }
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        }
    }

    fun goToSettings() {
        isGoToSeetings = true
        val myAppSettings = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, Uri.parse("package:" + this.packageName))
        myAppSettings.addCategory(Intent.CATEGORY_DEFAULT)
        myAppSettings.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        startActivity(myAppSettings)
    }

    /**
     * Check the GPS status. Ask to turn on if brightness_level_off.
     */
    private fun statusCheck() {
        val manager = getSystemService(Context.LOCATION_SERVICE) as LocationManager

        if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
            mDisplayNotifications?.displayErrorDialog(this,getString(R.string.permission_gps_access),getString(R.string.ok),getString(R.string.cancel))
        } else {
            try {
                BleEventBus.getInstance().register(this)
            } catch (e: IllegalArgumentException) {
            }
            if(isCreate) {
                mWiFiViewModel?.startScan(this)
            }
        }
    }

    fun turnOnGpsRequest(){
        startActivityForResult(Intent(android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS), 111)
    }

    fun turnOnWifiRequest(){
        startActivityForResult(Intent(android.provider.Settings.ACTION_WIFI_SETTINGS), 100)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        when (requestCode) {
            111 -> isGPSEnabled()
            100 -> {
                mWiFiViewModel?.checkWiFiConnection(this,ssid)
            }
            else -> super.onActivityResult(requestCode, resultCode, data)
        }
    }

    private fun isGPSEnabled() {
        isCreate = true
    }

    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu_wifi_listing, menu)//Menu Resource, Menu
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.action_refresh -> {
                mWiFiViewModel?.stopScan()
                mWiFiViewModel?.startScan(this)
                true
            }
            R.id.action_hotspot -> {
                mWiFiViewModel?.stopScan()
                if(type == "ap_mode") {
                    mDisplayNotifications?.displayWiFiPasswordDialog(this, "", ipAddress!!, "hotspot", type)
                } else {
                    mDisplayNotifications?.displayWiFiPasswordDialog(this, "", "", "hotspot", type)
                }
                true
            }
            android.R.id.home -> {
                onBackPressed()
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

    override fun onStop() {
        super.onStop()
        if(!isGoToSeetings) {
            isCreate = false
        } else {
            isGoToSeetings = false
        }
        mBLEViewModel?.removeHandlerBleConnect()
        mDisplayNotifications?.dismissDialog()
        try {
            BleEventBus.getInstance().unregister(this)
        } catch (e: IllegalArgumentException) {

        }

    }

    override fun onDestroy() {
        super.onDestroy()
        mWiFiViewModel?.stopScan()
        mDeviceViewModel?.stopSocket()
        mDisplayNotifications.dismissDialog()
        mBLEViewModel?.removeHandlerBleConnect()
    }

    override fun onBackPressed() {
        super.onBackPressed()
        mWiFiViewModel?.stopScan()
        mDeviceViewModel?.stopSocket()
        mDisplayNotifications.dismissDialog()
        mBLEViewModel?.removeHandlerBleConnect()
        finish()
        //overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right)

        val intent = Intent(this, DiscoverActivity::class.java)
        startActivity(intent)
    }

    @Subscribe
    fun onGattConnectionStateChangedEvent(event: GattConnectionStateChangedEvent) {

        if (event.getmGatt().device.address == bluetoothDevice?.address) {

            if (event.getmNewState() == GattConnectionState.STATE_CONNECTED) {
                Log.e("TAG", event.toString() + "---- Address : " + event.getmGatt().device.address)
                bluetoothGatt = event.getmGatt()
            } else if (event.getmStatus() == 133 && event.getmNewState() == BluetoothProfile.STATE_DISCONNECTED) {
                Log.e("TAG","disConnected 133")
                mBLEViewModel?.connectToDevice(this,bluetoothDevice!!)
            } else if (event.getmStatus() == BluetoothGatt.GATT_FAILURE && event.getmNewState() == BluetoothProfile.STATE_DISCONNECTED) {
                Log.e("TAG","disConnected GATT_FAILURE")
                mBLEViewModel?.connectToDevice(this,bluetoothDevice!!)
            } else if (event.getmNewState() == GattConnectionState.STATE_DISCONNECTED) {
                Log.e("TAG","disConnected")
            } else {
                Log.e("TAG","Connected else")
            }
        } else {
            Log.e("TAG","Else")
        }
    }

    @Subscribe
    fun onServiceDiscoveredEvent(event: ServiceDiscoveredEvent) {
        for (service in event.getmGatt().services) {
            if (service == null || service.uuid == null) {
            } else {
                if (AppConstant.DEVICE_SERVICE_UUID.equals(service.uuid.toString(),true)   && event.getmGatt().device.address.equals(bluetoothDevice?.address, ignoreCase = true)) {
                    var WIFI_CHAR: BluetoothGattCharacteristic = service.getCharacteristic(UUID.fromString(AppConstant.DEVICE_WIFI_UUID))

                    Handler(Looper.getMainLooper()).postDelayed({
                        //                            WriteSSID();
                        isGUIDWritten = true
                        Log.e("TAG",json.toString())
                        val gattCharacteristic = WIFI_CHAR
                        gattCharacteristic.value = json.toString().toByteArray()
                        bluetoothGatt?.writeCharacteristic(gattCharacteristic)
                    }, 2000)
                }

            }
        }
    }

    @Subscribe
    fun onCharacteristicWrite(event: CharacteristicWriteEvent) {
        Log.e("TAG", "onCharacteristicWrite: " + String(event.getmCharacteristic().value))
        Log.e("TAG",""+isGUIDWritten)
        if (isGUIDWritten) {
            writeSuccessful()
        }
    }

    private fun writeSuccessful(){
        runOnUiThread {
            Log.e("TAG", "runOnUiThread")
            mDisplayNotifications?.dismissDialog()
            mBLEViewModel?.removeHandlerBleConnect()
            isGUIDWritten = false
            mBLEViewModel?.DisplayWifiDialog(this@WifiListingActivity,ssid)
        }
    }

}
