package de.hft.geotracker.activities

import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Looper
import android.view.View
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.app.ActivityCompat.requestPermissions
import com.google.android.gms.location.*
import de.hft.geotracker.GeofenceBroadcastReceiver
import de.hft.geotracker.R
import de.hft.geotracker.retrofit.*
import kotlinx.android.synthetic.main.activity_home.*
import kotlinx.android.synthetic.main.dropdown_menu.*
import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.BufferedReader
import java.io.InputStreamReader


class MainActivity : AppCompatActivity() {
    lateinit var geofencingClient: GeofencingClient
    lateinit var geofence: Geofence
    lateinit var actionButton: TextView
    var running = false
    var accName: String? = null
    lateinit var accounts: ValuesTimetrackAccounts
    lateinit var service: GeofenceService
    lateinit var locationRequest: LocationRequest
    lateinit var fusedLocationClient: FusedLocationProviderClient
    lateinit var locationCallback: LocationCallback

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_home)

        //Get location data and permissions
        createLocationRequest()
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        if (ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION) !=
            PackageManager.PERMISSION_GRANTED
        ) {
            requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION), 1000)
        }
        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult?) {
                locationResult ?: return
            }
        }

        //React on geofence state
        this.getSharedPreferences("LOCATION", Context.MODE_PRIVATE)
            ?.edit()
            ?.putBoolean("ENABLED", false)
            ?.apply()
        getSharedPreferences("LOCATION", Context.MODE_PRIVATE)
            .registerOnSharedPreferenceChangeListener { sharedPreferences, key ->
                val btnState = sharedPreferences.getBoolean("ENABLED", false)

                println("Buttonstate: $btnState")
                if (btnState) {
                    button_start_stop?.setBackgroundColor(resources.getColor(R.color.logo_blue))
                } else {
                    button_start_stop?.setBackgroundColor(resources.getColor(R.color.colorPrimaryDark))
                    if (running) {
                        button_start_stop.toggle()
                        callStartStop()
                    }
                }
                button_start_stop.isEnabled = btnState
            }

        //JWToken lesen
        val fis = openFileInput("JWToken")
        val isr = InputStreamReader(fis)
        val bufferedReader = BufferedReader(isr)
        val stringBuilder = StringBuilder()
        var text: String? = null
        while ({ text = bufferedReader.readLine(); text }() != null) {
            stringBuilder.append(text)
        }
        val token = stringBuilder.toString()
        println("Token Main: " + token)
        //Retrofit declaration
        val httpClient = OkHttpClient.Builder()
        val interceptor = AuthenticationInterceptor(token)
        httpClient.addInterceptor(interceptor)
        val builder = Retrofit.Builder()
            .baseUrl("http://plesk.icaotix.de:5000")
            .addConverterFactory(GsonConverterFactory.create())
            .client(httpClient.build())
        val retrofit = builder.build()
        service = retrofit.create(GeofenceService::class.java)
        showUsername()

        //Get Timetrack Accounts
        val accountNames = mutableListOf<String>()
//        accountNames.add("None")
        val call = service.getAccounts()
        call.enqueue(object: Callback<EmbeddedAccounts> {
            override fun onResponse(
                call: Call<EmbeddedAccounts>,
                response: Response<EmbeddedAccounts>
            ) {
                if (response.isSuccessful) {
                    accounts = response.body()!!.accounts
                    accounts.entries.forEach {
                        accountNames.add(it.name + "")
                    }
                    initializeDropdown(accountNames)
                }
            }
            override fun onFailure(call: Call<EmbeddedAccounts>, t: Throwable) {
                accountNames.add("None")
                initializeDropdown(accountNames)
                Toast.makeText(this@MainActivity, "You dont have any Timetrack Accounts ", Toast.LENGTH_LONG)
                    .show()
            }
        })

        actionButton = findViewById(R.id.button_start_stop)
        actionButton.setOnClickListener {
            callStartStop()
        }

        my_toolbar.setOnMenuItemClickListener { menuItem ->
            when (menuItem.itemId) {
                R.id.settings -> {
                    startActivity(Intent(this, Settings::class.java))
                    println("Settings pressed")
                    true
                }
                R.id.logout -> {
                    deleteFile("JWToken")
                    startActivity(Intent(this, Login::class.java))
                    println("Logout pressed")
                    true
                }
                else -> false
            }
        }
    }

    private fun callStartStop() {
        running = !running
        if (running) {
            account_spinner.visibility = View.GONE
        } else {
            account_spinner.visibility = View.VISIBLE
        }
        if (!accName.isNullOrEmpty()) {
            val call = service.triggerTracking(accName!!)
            call.enqueue(object : Callback<ValuesTracking> {
                override fun onResponse(call: Call<ValuesTracking>, response: Response<ValuesTracking>) {
                    latitude.text = response.body()?.startdate
                    longitude.text = response.body()?.enddate
                    println("Tracking event successful!")
                }
                override fun onFailure(call: Call<ValuesTracking>, t: Throwable) {
                    println("Problem at start tracking: " + t.message)
                }
            })
        }
        println("StartStop pressed: $running")
        //ToDO call /track Endpoint
    }

    private fun showUsername() {
        val call = service.getUser()
        call.enqueue(object : Callback<ValuesUser> {
            override fun onResponse(call: Call<ValuesUser>, response: Response<ValuesUser>) {
                if (response.isSuccessful) {
                    val firstname = response.body()?.firstname
                    val location = response.body()?.location
                    lbl_username.text = "Hello " + firstname
                    println("Body: " + firstname)
                    if (location?.latitude == null) {
                        Toast.makeText(this@MainActivity, "No geofence set for you", Toast.LENGTH_LONG)
                            .show()
                    } else {
                        initializeGeofence(location?.latitude, location?.longitude, location?.radius)
                    }
                } else {
                    println("Response not successful: ${response.code()}")
                }
            }

            override fun onFailure(call: Call<ValuesUser>, t: Throwable) {
                println("Response 'whoami' failed. " + t.message)
            }
        })
    }
    private fun initializeDropdown(accountNames: MutableList<String>) {
        val spinner: Spinner = findViewById(R.id.account_spinner)
        // Create an ArrayAdapter using the string array and a default spinner layout
        val arrayAdapter = ArrayAdapter<String>(this, R.layout.spinner_layout, accountNames)
        arrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
        spinner.adapter = arrayAdapter
        spinner.onItemSelectedListener = object: AdapterView.OnItemSelectedListener {
            override fun onItemSelected(
                parent: AdapterView<*>?,
                view: View?,
                position: Int,
                id: Long
            ) {
                if (!accountNames.get(0).equals("None")) {
                    accName = accounts.entries.get(position).name
                    display_description.setText(accounts.entries.get(position).description)
                    display_revenue.setText(accounts.entries.get(position).revenue.toString())
                } else {
                    display_description.visibility = View.GONE
                    display_description_layout.visibility = View.GONE
                    display_revenue.visibility = View.GONE
                    display_revenue_layout.visibility = View.GONE
                }
                println("Selected: " + accountNames.get(position))
            }
            override fun onNothingSelected(parent: AdapterView<*>?) {
                println("Nothing selected")
            }
        }
    }
    private fun initializeGeofence(lat: Double, long: Double, rad: Float) {
        geofencingClient = LocationServices.getGeofencingClient(this)
        geofence = Geofence.Builder().setRequestId("Test")
            .setCircularRegion(lat, long, rad)
            .setExpirationDuration(Geofence.NEVER_EXPIRE)
            .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER or Geofence.GEOFENCE_TRANSITION_EXIT)
            .build()
        geofencingClient.addGeofences(getGeofencingRequest(), geofencePendingIntent)?.run {
            addOnSuccessListener {
                println("Geofence added with: latitude: $lat longitude: $long radius: $rad")
            }
            addOnFailureListener {
                println("Error: " + it.stackTrace.forEach { println(it.toString()) })
            }
        }
    }

    private fun getGeofencingRequest(): GeofencingRequest {
        return GeofencingRequest.Builder().apply {
            setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
            addGeofence(geofence)
        }.build()
    }

    private val geofencePendingIntent: PendingIntent by lazy {
        val intent = Intent(this, GeofenceBroadcastReceiver::class.java)
        // We use FLAG_UPDATE_CURRENT so that we get the same pending intent back when calling
        // addGeofences() and removeGeofences().
        PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
    }

    override fun onResume() {
        super.onResume()
        startLocationUpdates()
    }
    private fun startLocationUpdates() {
        fusedLocationClient.requestLocationUpdates(
            locationRequest,
            locationCallback,
            Looper.getMainLooper()
        )
    }

    private fun createLocationRequest() {
        locationRequest = LocationRequest.create().apply {
            interval = 10000
            fastestInterval = 5000
            priority = LocationRequest.PRIORITY_HIGH_ACCURACY
        }
    }

    override fun onBackPressed() {
    }

}
