package xyz.r0r5chach.dermy_app.fragments

import android.content.SharedPreferences
import android.database.sqlite.SQLiteDatabase
import android.graphics.BitmapFactory
import android.os.Build
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
import androidx.lifecycle.findViewTreeViewModelStoreOwner
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.RequestBody
import xyz.r0r5chach.dermy_app.LogsAdapter
import xyz.r0r5chach.dermy_app.MolesAdapter
import xyz.r0r5chach.dermy_app.PredictionMode
import xyz.r0r5chach.dermy_app.R
import xyz.r0r5chach.dermy_app.api.DermyApi
import xyz.r0r5chach.dermy_app.api.DermyApiService
import xyz.r0r5chach.dermy_app.api.Prediction
import xyz.r0r5chach.dermy_app.db.DBProcess
import xyz.r0r5chach.dermy_app.db.DermyDatabase
import xyz.r0r5chach.dermy_app.db.Entities
import xyz.r0r5chach.dermy_app.db.Tables
import xyz.r0r5chach.dermy_app.map.locations.Location
import java.io.ByteArrayOutputStream
import java.io.File
import java.time.Instant

class MoleFragment(private val mole: Entities.Mole, private val mode: PredictionMode, val db: DermyDatabase) : Fragment(R.layout.fragment_mole) {


    @RequiresApi(Build.VERSION_CODES.O)
    @OptIn(DelicateCoroutinesApi::class)
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
        val api = DermyApi(preferences.getString("instance_url", null)!!).getInstance()
        val apiKey = preferences.getString("api_key", null)

        val moleImage = view.findViewById<ImageView>(R.id.mole_image)
        val image = File(requireContext().filesDir, "${mole.id}.jpg").absolutePath
        val moleSide = view.findViewById<EditText>(R.id.side_value)
        val moleBodyPart = view.findViewById<EditText>(R.id.body_part_value)
        val benignPrediction = view.findViewById<EditText>(R.id.benign_prediction_value)
        val malignantPrediction = view.findViewById<EditText>(R.id.malignant_prediction_value)

        val list = view.findViewById<RecyclerView>(R.id.log_list)
        val emptyList = view.findViewById<TextView>(R.id.log_empty_text)
        val logs = mutableListOf<Entities.LogEntry>()

        with(db.readableDatabase.query(Tables.MOLES.toString(), null, null, null, null, null, null)) {
            while (moveToNext()) {
                logs.add(
                    Entities.LogEntry(
                        getString(getColumnIndexOrThrow("id")),
                        getString(getColumnIndexOrThrow("moleId")),
                        Instant.parse(getString(getColumnIndexOrThrow("dateCreated"))),
                        getString(getColumnIndexOrThrow("contents"))
                    )
                )
            }
            close()
        }
        val adapter = LogsAdapter(logs, requireContext().filesDir)
        list.layoutManager = LinearLayoutManager(requireContext())
        list.adapter = adapter

        if (adapter.itemCount == 0) {
            list.visibility = View.GONE
            emptyList.visibility = View.VISIBLE
        }
        else {
            list.visibility = View.VISIBLE
            emptyList.visibility = View.GONE
        }

        val saveButton = view.findViewById<ImageButton>(R.id.mole_save_button)

        if (mode == PredictionMode.NEW || mode == PredictionMode.UPDATE) {
            if (mode == PredictionMode.NEW) {
                saveButton.visibility = View.VISIBLE
            }
            else {
                saveButton.visibility = View.GONE

            }
            val toast = Toast.makeText(context, "Error making prediction", Toast.LENGTH_SHORT)

            GlobalScope.launch {
                try {
                    val result = api.predict(
                        apiKey!!, RequestBody.create(
                            MediaType.get("application/octet-stream"),
                            image.toByteArray()
                        )
                    )

                    if (result.containsKey("benign_probability") && result.containsKey("malignant_probability")) {
                        mole.prediction = Prediction(
                            result["benign_probability"]!!.toFloat(),
                            result["malignant_probability"]!!.toFloat()
                        )
                        benignPrediction.setText((mole.prediction!!.benign * 100).toString())
                        malignantPrediction.setText((mole.prediction!!.malignant * 100).toString())
                    }
                }
                catch (e: Exception) {
                    toast.show()
                }
            }
        }
        else {
            saveButton.visibility = View.GONE
        }

        moleImage.setImageBitmap(BitmapFactory.decodeFile(image))
        moleSide.setText(mole.location?.side.toString())
        moleBodyPart.setText(mole.location?.bodyPart.toString())
        benignPrediction.setText((mole.prediction?.benign?.times(100)).toString())
        malignantPrediction.setText((mole.prediction?.malignant?.times(100))toString())

        //TODO: On new prediction pressed: CameraFragment -> take photo -> MoleFragment -> predict -> update db
        //TODO: On save pressed: insert mole to db
        //TODO: On new log pressed: Popup -> save input from popup as contents -> insert new Log
    }
}
