package org.foxarmy.barcodescannerforemployees.fragments

import android.content.Intent
import android.os.Bundle
import android.provider.BaseColumns
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.ImageView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.view.children
import androidx.fragment.app.Fragment
import androidx.gridlayout.widget.GridLayout
import org.foxarmy.barcodescannerforemployees.AbstractProductContract
import org.foxarmy.barcodescannerforemployees.DBStorageController
import org.foxarmy.barcodescannerforemployees.ProductContract
import org.foxarmy.barcodescannerforemployees.R
import org.foxarmy.barcodescannerforemployees.activities.AddProductActivity
import org.foxarmy.barcodescannerforemployees.databinding.FragmentShelfBinding
import org.foxarmy.barcodescannerforemployees.dataclasses.Product
import org.foxarmy.barcodescannerforemployees.views.ProductView
import kotlin.concurrent.thread

class ShelfFragment : Fragment() {

    private lateinit var binding: FragmentShelfBinding
    private var updateInProgress = false

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentShelfBinding.inflate(layoutInflater)

        fillUpSortBySpinner()

        binding.spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onNothingSelected(parent: AdapterView<*>?) {
                updateContent()
            }

            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
                updateContent()
            }
        }

        updateContent()

        return binding.root
    }

    fun updateSelected() {
        val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)

        var updated = false
        for (view: ProductView in grv?.children!!.iterator() as Iterator<ProductView>) {
            if (view.isProductSelected) {
                val addProductIntent = Intent(requireContext(), AddProductActivity::class.java)
                val extras = Bundle()
                extras.putParcelable("product", view.product)
                addProductIntent.putExtras(extras)
                ContextCompat.startActivity(requireContext(), addProductIntent, extras)

                updated = true
            }
        }

        if (!updated) {
            Toast.makeText(requireContext(), "Nothing to update", Toast.LENGTH_SHORT).show()
        }
        updateContent()
    }

    private fun fillUpSortBySpinner() {
        val sorts = mutableListOf("Name", "Category", "Freshness", "Date of production", "Date of expiry")

        val arrayAdapter =
            ArrayAdapter(requireContext(), androidx.appcompat.R.layout.support_simple_spinner_dropdown_item, sorts)
        arrayAdapter.setDropDownViewResource(androidx.appcompat.R.layout.support_simple_spinner_dropdown_item)
        binding.spinner.adapter = arrayAdapter
    }

    override fun onResume() {
        super.onResume()

        updateContent()
    }

    fun updateContent() {
        thread {
            if (updateInProgress) return@thread
            updateInProgress = true
            val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)
            activity!!.runOnUiThread {
                grv?.removeAllViews()
            }

            val db = DBStorageController(requireContext()).readableDatabase
            val projection = arrayOf(
                BaseColumns._ID,
                ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID,
                ProductContract.ProductEntry.AMOUNT,
                ProductContract.ProductEntry.DATE_OF_PRODUCTION,
                ProductContract.ProductEntry.EXPIRY_DATE,
            )

            var orderBy: String = ""

            when (binding.spinner.selectedItem) {
                "Name" -> {
                    orderBy =
                        "(SELECT ${AbstractProductContract.AbstractProductEntry.PRODUCT_NAME} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC"
                }

                "Category" -> {
                    orderBy =
                        "(SELECT ${AbstractProductContract.AbstractProductEntry.CATEGORY} FROM ${AbstractProductContract.AbstractProductEntry.TABLE_NAME} WHERE ${BaseColumns._ID} = ${ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID}) ASC"
                }
// Wow, I wrote this on first try but unfortunately SQLite can't do that :(
// I'll leave it here as a memory.
//                "Freshness" -> {
//                    orderBy =
//                        "(SELECT ( (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday('now', 'localtime')) / (julianday(${ProductContract.ProductEntry.EXPIRY_DATE}) - julianday(${ProductContract.ProductEntry.DATE_OF_PRODUCTION})) )) ASC"
//                }

                "Date of production" -> {
                    orderBy = "${ProductContract.ProductEntry.DATE_OF_PRODUCTION} ASC"
                }

                "Date of expiry" -> {
                    orderBy = "${ProductContract.ProductEntry.EXPIRY_DATE} ASC"
                }
            }

            val cursor = db.query(ProductContract.ProductEntry.TABLE_NAME, projection, null, null, null, null, orderBy)

            val products = mutableListOf<Product>()

            with(cursor) {
                while (moveToNext()) {
                    val productId = getInt(getColumnIndexOrThrow(BaseColumns._ID))
                    val abstractProductId =
                        getInt(getColumnIndexOrThrow(ProductContract.ProductEntry.ABSTRACT_PRODUCT_ID))
                    val amount = getInt(getColumnIndexOrThrow(ProductContract.ProductEntry.AMOUNT))
                    val dateOfProduction =
                        getLong(getColumnIndexOrThrow(ProductContract.ProductEntry.DATE_OF_PRODUCTION))
                    val dateOfExpiry = getLong(getColumnIndexOrThrow(ProductContract.ProductEntry.EXPIRY_DATE))

                    val product = Product(productId, abstractProductId, amount, dateOfProduction, dateOfExpiry)

                    if (binding.spinner.selectedItem == "Freshness") {
                        products.add(product)
                    } else {
                        val productView = ProductView(
                            requireActivity(),
                            requireContext(),
                            product
                        )
                        activity!!.runOnUiThread {
                            grv?.addView(productView)
                        }
                    }
                }
            }

            products.sortWith(compareByDescending { it.freshness })

            for (product in products.iterator()) {
                val productView = ProductView(
                    requireActivity(),
                    requireContext(),
                    product
                )
                activity!!.runOnUiThread {
                    grv?.addView(productView)
                }
            }
            updateInProgress = false
        }
    }

    fun removeSelected() {
        thread {
            val grv = view?.findViewById<GridLayout>(R.id.contentGridLayout)

            val db = DBStorageController(requireContext())
            var deleted = false
            for (view: ProductView in grv?.children!!.iterator() as Iterator<ProductView>) {
                activity!!.runOnUiThread {
                    view.findViewById<ImageView>(R.id.productPicture).setImageURI(null)
                }
                if (view.isProductSelected) {
                    db.eraseProduct(db.writableDatabase, view.product.id)
                    deleted = true
                }
            }

            if (!deleted) {
                activity!!.runOnUiThread {
                    Toast.makeText(requireContext(), "Nothing to delete", Toast.LENGTH_SHORT).show()
                }
            }
            updateContent()
        }
    }
}