package net.pokeranalytics.android.ui.fragment.components

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import com.google.android.material.snackbar.Snackbar
import io.realm.RealmObject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter

/**
 * Deletable Item Fragment
 * Don't forget to add a CoordinatorLayout at the top of your XML
 * if you want to display correctly the snack bar
 */
abstract class DeletableItemFragment : RealmFragment() {

	companion object {
		const val REQUEST_CODE_DELETION = 1000
	}

	lateinit var dataListAdapter: RowRepresentableAdapter

	private var deletedItem: RealmObject? = null
	private var itemHasBeenReInserted: Boolean = false
	private var lastDeletedItemPosition: Int = 0

	private var mainLayout: ViewGroup? = null
	private var snackBar: Snackbar? = null

	abstract fun deletableItems() : List<Deletable>

	override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
		super.onViewCreated(view, savedInstanceState)
		this.mainLayout = view.findViewById(R.id.mainLayout)
	}

	override fun onPause() {
		super.onPause()
		snackBar?.dismiss()
	}

	override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
		super.onActivityResult(requestCode, resultCode, data)
		if (requestCode == REQUEST_CODE_DELETION && resultCode == Activity.RESULT_OK) {

			val itemToDeleteId = data?.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName)
			itemToDeleteId?.let { id ->
				GlobalScope.launch(Dispatchers.Main) {
					delay(300)
					deleteItem(dataListAdapter, deletableItems(), id)
				}
			}
		}
	}

	/**
	 * Delete item
	 * [dataListAdapter]: Adapter to update
	 * [items]: List of items which contains the element to delete
	 * [itemId]: Id of the item to delete
	 */
	fun deleteItem(dataListAdapter: RowRepresentableAdapter, items: List<Deletable>, itemId: String) {

		if (isDetached || activity == null) {
			return
		}

		this.dataListAdapter = dataListAdapter

		// Save the delete position & create a copy of the object
		val itemPosition = items.indexOfFirst { it.id == itemId }
		val itemToDelete = items.find { it.id == itemId }

		if (itemToDelete is RealmObject && itemPosition != -1) {

			// Check if the object is valid for the deletion
			if (itemToDelete.isValidForDelete(this.getRealm())) {
				deletedItem = getRealm().copyFromRealm(itemToDelete)
				lastDeletedItemPosition = itemPosition
				getRealm().executeTransaction {
					itemToDelete.deleteDependencies(it)
					itemToDelete.deleteFromRealm()
				}
				itemHasBeenReInserted = false
				updateUIAfterDeletion(itemPosition)
				showUndoSnackBar()
			} else {
				dataListAdapter.notifyItemChanged(itemPosition)
				val status = itemToDelete.getDeleteStatus(requireContext(), this.getRealm())
				val message = itemToDelete.getFailedDeleteMessage(status)
				val builder = AlertDialog.Builder(requireContext())
					.setMessage(message)
					.setNegativeButton(R.string.ok, null)
				builder.show()
			}
		}
	}

	/**
	 * Show undo snack bar
	 */
	private fun showUndoSnackBar() {
		val message = String.format(getString(R.string.data_deleted))
		this.mainLayout?.let { view ->
			snackBar = Snackbar.make(view, message, Snackbar.LENGTH_INDEFINITE)
			snackBar?.setAction(R.string.cancel) {
				if (!itemHasBeenReInserted) {
					itemHasBeenReInserted = true
					getRealm().executeTransaction { realm ->
						deletedItem?.let {
							val item = realm.copyToRealmOrUpdate(it)
							updateUIAfterUndoDeletion(item)
						}
					}
				}
			}
			snackBar?.show()
		} ?: run {
			throw IllegalStateException("mainLayout is not defined")
		}
	}

	/**
	 * Called once the object has been deleted
	 */
	open fun updateUIAfterDeletion(itemPosition: Int) {
		dataListAdapter.notifyItemRemoved(itemPosition)
	}

	/**
	 * Called once the object has been restored
	 */
	open fun updateUIAfterUndoDeletion(newItem: RealmObject) {
		dataListAdapter.notifyItemInserted(lastDeletedItemPosition)
	}

}