package net.pokeranalytics.android.ui.fragment.data

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.chip.ChipGroup
import kotlinx.android.synthetic.main.fragment_custom_view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.CustomField
import net.pokeranalytics.android.model.realm.CustomFieldEntry
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.ChipGroupExtension
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.extensions.showAlertDialog
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowRepresentableEditDescriptor
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomFieldRow
import net.pokeranalytics.android.ui.view.rowrepresentable.SimpleRow
import net.pokeranalytics.android.util.NULL_TEXT
import java.util.*

/**
 * Custom EditableDataFragment to manage the Transaction data
 */
class CustomFieldDataFragment : EditableDataFragment(), StaticRowRepresentableDataSource {

	// Return the item as a Custom TypedCSVField object
	private val customField: CustomField
		get() {
			return this.item as CustomField
		}

	private val itemTouchHelper = ItemTouchHelper(object : ItemTouchHelper.Callback() {

		var dragFrom = -1
		var dragTo = -1

		override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
			return if (viewHolder.adapterPosition <= 2) {
				return 0
			} else {
				makeFlag(
					ItemTouchHelper.ACTION_STATE_DRAG, ItemTouchHelper.DOWN
							or ItemTouchHelper.UP or ItemTouchHelper.START or ItemTouchHelper.END
				)
			}
		}

		override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {

			if (target.adapterPosition <= 2) {
				return false
			}

			val fromPosition = viewHolder.adapterPosition
			val toPosition = target.adapterPosition

			if (dragFrom == -1) {
				dragFrom = viewHolder.adapterPosition - 1
			}
			dragTo = target.adapterPosition - 1

			rowRepresentableAdapter.notifyItemMoved(fromPosition, toPosition)

			return true
		}

		override fun onMoved(
			recyclerView: RecyclerView,
			viewHolder: RecyclerView.ViewHolder,
			fromPos: Int,
			target: RecyclerView.ViewHolder,
			toPos: Int,
			x: Int,
			y: Int
		) {
			super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y)

			Collections.swap(customField.entries, fromPos - (CustomFieldRow.values().size + 1), toPos - (CustomFieldRow.values().size + 1))
			customField.entries.forEachIndexed { index, rowRepresentable ->
				val entry = rowRepresentable as CustomFieldEntry
				entry.order = index
			}

		}

		override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
			super.clearView(recyclerView, viewHolder)
			dragFrom = -1
			dragTo = -1
		}

		override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
		}
	})


	override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
		super.onCreateView(inflater, container, savedInstanceState)
		return inflater.inflate(R.layout.fragment_custom_view, container, false)
	}


	override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
		super.onViewCreated(view, savedInstanceState)
		initUI()
	}

	override fun getDataSource(): RowRepresentableDataSource {
		return this
	}

	override fun adapterRows(): List<RowRepresentable>? {
		return customField.adapterRows()
	}

	override fun stringForRow(row: RowRepresentable): String {
		return when (row) {
			SimpleRow.NAME -> if (customField.name.isNotEmpty()) customField.name else NULL_TEXT
			else -> super.stringForRow(row)
		}
	}

	override fun boolForRow(row: RowRepresentable): Boolean {
		return when (row) {
			CustomFieldRow.COPY_ON_DUPLICATE -> customField.duplicateValue
			CustomFieldRow.TYPE -> isUpdating
			else -> super.boolForRow(row)
		}
	}

	override fun intForRow(row: RowRepresentable): Int {
		return when (row) {
			CustomFieldRow.TYPE -> customField.type
			else -> super.intForRow(row)
		}
	}

	override fun editDescriptors(row: RowRepresentable): ArrayList<RowRepresentableEditDescriptor>? {
		return when (row) {
			SimpleRow.NAME -> row.editingDescriptors(mapOf("defaultValue" to this.customField.name))
			is CustomFieldEntry -> row.editingDescriptors(mapOf("defaultValue" to row.value))
			else -> null
		}
	}

	override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
		when (row) {
			is CustomFieldEntry -> {
				val data = customField.editDescriptors(row)
				BottomSheetFragment.create(fragmentManager, row, this, data, isClearable = false, isDeletable = true)
			}
			else -> super.onRowSelected(position, row, fromAction)
		}
	}

	override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
		when (row) {
			is CustomFieldEntry -> {
				row.updateValue(value, row)
				customField.updateRowRepresentation()
				rowRepresentableAdapter.notifyDataSetChanged()
			}
			CustomFieldRow.TYPE -> {
				customField.updateValue(value, row)
				updateUI()
				rowRepresentableAdapter.notifyDataSetChanged()
			}
			else -> super.onRowValueChanged(value, row)
		}
	}

	override fun onRowDeleted(row: RowRepresentable) {
		super.onRowDeleted(row)
		when (row) {
			is CustomFieldEntry -> {
				if (!row.isValidForDelete(getRealm())) {
					val status = row.getDeleteStatus(requireContext(), getRealm())
					val message = row.getFailedDeleteMessage(status)
					showAlertDialog(requireContext(), R.string.cf_entry_delete_popup_title, message, showCancelButton = true, positiveAction = {
						customField.deleteEntry(row)
						rowRepresentableAdapter.notifyDataSetChanged()
					})
				} else {
					customField.deleteEntry(row)
					rowRepresentableAdapter.notifyDataSetChanged()
				}
			}
		}
	}

	/**
	 * Init UI
	 */
	private fun initUI() {
		customField.updateRowRepresentation()
		bottomBar.translationY = 72f.px
		bottomBar.visibility = View.VISIBLE

		if (customField.sortCondition == CustomField.Sort.DEFAULT.uniqueIdentifier) {
			itemTouchHelper.attachToRecyclerView(recyclerView)
		} else {
			itemTouchHelper.attachToRecyclerView(null)
		}

		when (customField.sortCondition) {
			CustomField.Sort.DEFAULT.uniqueIdentifier -> sortDefault.isChecked = true
			CustomField.Sort.ASCENDING.uniqueIdentifier -> sortAscending.isChecked = true
			CustomField.Sort.DESCENDING.uniqueIdentifier -> sortDescending.isChecked = true
		}

		addItem.setOnClickListener {
			val customFieldEntry = customField.addEntry()
			rowRepresentableAdapter.notifyDataSetChanged()
			onRowSelected(-1, customFieldEntry)
		}

		sortChoices.setOnCheckedChangeListener(object : ChipGroupExtension.SingleSelectionOnCheckedListener() {
			override fun onCheckedChanged(group: ChipGroup, checkedId: Int) {
				super.onCheckedChanged(group, checkedId)

				@SuppressWarnings
				if (checkedId < 0) { // when unchecked, checkedId returns -1, causing a crash
					return
				}

				when (checkedId) {
					R.id.sortDefault -> customField.sortCondition = CustomField.Sort.DEFAULT.uniqueIdentifier
					R.id.sortAscending -> customField.sortCondition = CustomField.Sort.ASCENDING.uniqueIdentifier
					R.id.sortDescending -> customField.sortCondition = CustomField.Sort.DESCENDING.uniqueIdentifier
				}

				if (customField.sortCondition == CustomField.Sort.DEFAULT.uniqueIdentifier) {
					itemTouchHelper.attachToRecyclerView(recyclerView)
				} else {
					itemTouchHelper.attachToRecyclerView(null)
				}
				rowRepresentableAdapter.notifyDataSetChanged()
			}
		})

		updateUI()
		rowRepresentableAdapter.notifyDataSetChanged()

		if (!this.deleteButtonShouldAppear) {
			rowRepresentableForPosition(0)?.let {
				onRowSelected(0, it)
			}
		}
	}


	/**
	 * Update UI
	 */
	private fun updateUI() {
		if (customField.type == CustomField.Type.LIST.uniqueIdentifier) {
			bottomBar.animate().translationY(0f.px)
				.setInterpolator(FastOutSlowInInterpolator())
				.start()
		} else {
			bottomBar.animate().translationY(72f.px)
				.setInterpolator(FastOutSlowInInterpolator())
				.start()
		}
	}

	override fun onDataSaved() {
		super.onDataSaved()

		this.customField.cleanupEntries()

	}

}