package de.hft.geotracker.activities

import android.Manifest
import android.Manifest.permission.ACCESS_COARSE_LOCATION
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.app.AlertDialog
import android.app.PendingIntent
import android.content.Context
import android.content.DialogInterface
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 androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.gms.location.*
import de.hft.geotracker.GeofenceBroadcastReceiver
import de.hft.geotracker.R
import de.hft.geotracker.RecordsAdapter
import de.hft.geotracker.retrofit.*
import kotlinx.android.synthetic.main.activity_home.*
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
    var workingSince: 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 isInside = sharedPreferences.getBoolean("ENABLED", false)

                println("Is inside? -> $isInside")
                if (isInside) {
                    button_start_stop?.text = getString(R.string.start)
                    button_start_stop?.setBackgroundColor(resources.getColor(R.color.logo_blue))
               } else {
                    button_start_stop?.setBackgroundColor(resources.getColor(R.color.colorPrimaryDark))
                    if (running) {
                        callStartStop()
                    }
                    button_start_stop?.text = getString(R.string.outside_place)
                }
                button_start_stop.isEnabled = isInside
            }

        //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()
        updateRecyclerView()

        actionButton = findViewById(R.id.button_start_stop)
        actionButton.setBackgroundColor(resources.getColor(R.color.colorPrimaryDark))
        actionButton.setOnClickListener {
            if (running) {
                val builder: AlertDialog.Builder = AlertDialog.Builder(this)
                builder.setTitle(R.string.app_name)
                builder.setMessage("Do you want to stop?")
                builder.setIcon(R.drawable.ic_logo)
                builder.setPositiveButton("Yes", object : DialogInterface.OnClickListener {
                    override fun onClick(dialog: DialogInterface, id: Int) {
                        callStartStop()
                        dialog.dismiss()
                    }
                })
                builder.setNegativeButton("No", object : DialogInterface.OnClickListener {
                    override fun onClick(dialog: DialogInterface, id: Int) {
                        dialog.dismiss()
                    }
                })
                val alert: AlertDialog = builder.create()
                alert.show()
            } else {
                callStartStop()
            }
        }

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



    }

    private fun updateRecyclerView() {
        //Recycler View
        val recView: RecyclerView = records_list
        recView.setHasFixedSize(true)
        val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(this)
        val adapter = RecordsAdapter()
        val recordList = ArrayList<RecordEntry>()
        
        val call = service.getTodaysRecords()
        call.enqueue(object: Callback<EmbeddedRecords> {
            override fun onResponse(call: Call<EmbeddedRecords>, response: Response<EmbeddedRecords>) {
                if (response.isSuccessful) {
                    val entries = response.body()!!.records.entries
                    if (!entries.isEmpty()) {
                        entries.forEach {
                            recordList.add(RecordEntry(it.startdate.substring(11, 16)
                                , it.enddate.substring(11, 16)
                                , it.duration))
                        }
                        if (running) {
                            recordList.add(RecordEntry(workingSince!!, "PENDING", -1))
                        }
                        adapter.data = recordList
                        recView.layoutManager = layoutManager
                        recView.adapter = adapter
                    } else {
                        println("No Records!")
                    }

                } else {
                    println("Response for todays records was not successful")
                }
            }
            override fun onFailure(call: Call<EmbeddedRecords>, t: Throwable) {
                println("Getting todays records failed")
            }

        })
    }

    private fun callStartStop() {
        running = !running
        if (running) {
            account_spinner.visibility = View.GONE
            button_start_stop?.text = getString(R.string.stop)
        } else {
            account_spinner.visibility = View.VISIBLE
            button_start_stop?.text = getString(R.string.start)
        }
        if (!accName.isNullOrEmpty()) {
            val call = service.triggerTracking(accName!!)
            call.enqueue(object : Callback<ValuesTracking> {
                override fun onResponse(call: Call<ValuesTracking>, response: Response<ValuesTracking>) {
                    workingSince = response.body()?.startdate?.substring(11, 16)
                    updateRecyclerView()
                    println("Tracking event successful!")
                }
                override fun onFailure(call: Call<ValuesTracking>, t: Throwable) {
                    println("Problem at start tracking: " + t.message)
                }
            })
        } else {
            println("Accounts list is emty")
        }
        println("StartStop pressed: $running")
    }

    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
                    val username = response.body()?.username
                    getTimetrackAccounts(username!!)
                    lbl_username.text = "Hello " + firstname
                    if (location?.latitude == null) {
                        button_start_stop?.text = "No geofence set for you"
                        button_start_stop?.setBackgroundColor(resources.getColor(R.color.colorPrimaryDark))
                        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 getTimetrackAccounts(user: String) {
        val accountNames = mutableListOf<String>()
//        accountNames.add("None")
        val call = service.getAccounts(user)
        call.enqueue(object: Callback<EmbeddedAccounts> {
            override fun onResponse(
                call: Call<EmbeddedAccounts>,
                response: Response<EmbeddedAccounts>
            ) {
                if (response.isSuccessful) {
                    accounts = response.body()!!.accounts
                    if (!accounts.entries.isEmpty()) {
                        accounts.entries.forEach {
                            accountNames.add(it.name + "")
                        }
                    } else {
                        accountNames.add("None")
                        initializeDropdown(accountNames)
                        display_description.setText("You dont have any Timetrack Accounts")
                        Toast.makeText(this@MainActivity, "You dont have any Timetrack Accounts", Toast.LENGTH_LONG)
                            .show()
                    }

                    initializeDropdown(accountNames)
                    println("Dropdown initialized")
                }
            }
            override fun onFailure(call: Call<EmbeddedAccounts>, t: Throwable) {
                println("Failed to get accounts")
            }
        })
    }
    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_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()
        if (ActivityCompat.checkSelfPermission(
                this,
                ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION), 1000)
        }
        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() {
        if (ActivityCompat.checkSelfPermission(
                this,
                ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.ACCESS_COARSE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION), 1000)
        }
        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() {
    }

}

class RecordEntry(from: String, to: String, duration: Int) {
    val from = from
    val to = to
    val duration = duration
}


