package net.pokeranalytics.android.ui.fragment

import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.*
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.RealmObject
import kotlinx.android.synthetic.main.fragment_editable_data.*
import kotlinx.android.synthetic.main.fragment_editable_data.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.exceptions.ConfigurationException
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Deletable
import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.interfaces.Savable
import net.pokeranalytics.android.model.interfaces.SaveValidityStatus
import net.pokeranalytics.android.ui.activity.DataListActivity
import net.pokeranalytics.android.ui.activity.EditableDataActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDataSource
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.view.RowRepresentable


open class EditableDataFragment : PokerAnalyticsFragment(), RowRepresentableDelegate {

	lateinit var parentActivity: PokerAnalyticsActivity
	lateinit var item: RealmObject
	lateinit var liveDataType: LiveData
	lateinit var rowRepresentableAdapter: RowRepresentableAdapter

	private var editableMenu: Menu? = null
	private var dataType: Int? = null
	private var primaryKey: String? = null

	var isUpdating = false
	var shouldOpenKeyboard = true

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

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

	override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) {
		inflater?.inflate(R.menu.toolbar_editable_data, menu)
		this.editableMenu = menu
		updateMenuUI()
		super.onCreateOptionsMenu(menu, inflater)
	}


	override fun onOptionsItemSelected(item: MenuItem?): Boolean {
		when (item!!.itemId) {
			R.id.save -> saveData()
			R.id.delete -> deleteData()
		}
		return true
	}

	override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
		BottomSheetFragment.create(fragmentManager, row, this, getDataSource().editDescriptors(row))
	}

	override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
		this.getRealm().executeTransaction {
			(this.item as Editable).updateValue(value, row)
		}
		rowRepresentableAdapter.refreshRow(row)
	}

	/**
	 * Init UI
	 */
	private fun initUI() {
		parentActivity = activity as PokerAnalyticsActivity
		parentActivity.setSupportActionBar(toolbar)
		parentActivity.supportActionBar?.setDisplayHomeAsUpEnabled(true)
		setHasOptionsMenu(true)

		val viewManager = LinearLayoutManager(requireContext())

		recyclerView.apply {
			setHasFixedSize(true)
			layoutManager = viewManager
		}
	}

	/**
	 * Return the data source
	 */
	open fun getDataSource(): RowRepresentableDataSource {
		return this.item as RowRepresentableDataSource
	}

	/**
	 * Init data
	 */
	private fun initData() {
		if (this.dataType != null) {
			val proxyItem: RealmObject? = this.liveDataType.getData(this.getRealm(), primaryKey)
			proxyItem?.let {
				//TODO: Localize
				this.appBar.toolbar.title = "Update ${this.liveDataType.localizedTitle(this.parentActivity).toLowerCase().capitalize()}"
				isUpdating = true
			} ?: run {
				//TODO: Localize
				this.appBar.toolbar.title = this.liveDataType.newEntityLocalizedTitle(requireContext())
			}
			this.item = this.liveDataType.updateOrCreate(this.getRealm(), primaryKey)

			val dataSource = getDataSource()
			this.rowRepresentableAdapter = RowRepresentableAdapter(getDataSource(), this)
			this.recyclerView.adapter = rowRepresentableAdapter

			// When creating an object, open automatically the keyboard for the first row
			if (!isUpdating && shouldOpenKeyboard) {
				val row = dataSource.adapterRows()?.firstOrNull()
				row?.let {
					onRowSelected(0, it)
				}
			}
		}
	}

	/**
	 * Update menu UI
	 */
	private fun updateMenuUI() {
		editableMenu?.findItem(R.id.delete)?.isVisible = isUpdating
		editableMenu?.findItem(R.id.save)?.isVisible = true
	}

	/**
	 * Save data
	 */
	fun saveData() {

		val savable = this.item
		when (savable) {
			is Savable -> {
				val status = savable.getSaveValidityStatus(realm = this.getRealm())
				when (status) {
					SaveValidityStatus.VALID -> {
						this.getRealm().executeTransaction {
							val managedItem = it.copyToRealmOrUpdate(this.item)
							if (managedItem is Savable) {
								val uniqueIdentifier = (managedItem as Savable).id
								finishActivityWithResult(uniqueIdentifier)
							}

//							if (managedItem is Bankroll) {
//								managedItem.currency?.refreshRelatedRatedValues(it)
//							}
//
//							val uniqueIdentifier = (managedItem as Savable).id
//							finishActivityWithResult(uniqueIdentifier)
						}
					}
					else -> {
						val message = savable.getFailedSaveMessage(status)
						val builder = AlertDialog.Builder(requireContext())
							.setMessage(message)
							.setNegativeButton(R.string.ok, null)
						builder.show()
					}
				}

			} else -> {
				throw ConfigurationException("Save action called on un-Savable object")
			}
		}

	}

	/**
	 * Delete data
	 */
	private fun deleteData() {

		val deletable = this.item as Deletable
		val realm = this.getRealm()

		if (deletable.isValidForDelete(realm)) {
			val intent = Intent()
			intent.putExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName, true)
			activity?.setResult(RESULT_OK, intent)
			activity?.finish()
		} else {
			val message = deletable.getFailedDeleteMessage()
			val builder = AlertDialog.Builder(requireContext())
				.setMessage(message)
				.setNegativeButton(R.string.ok, null)
			builder.show()
		}
	}

	/**
	 * Finish the activity with a result
	 */
	private fun finishActivityWithResult(uniqueIdentifier: String) {
		val intent = Intent()
		intent.putExtra(EditableDataActivity.IntentKey.DATA_TYPE.keyName, dataType)
		intent.putExtra(EditableDataActivity.IntentKey.PRIMARY_KEY.keyName, uniqueIdentifier)
		activity?.setResult(RESULT_OK, intent)
		activity?.finish()
	}

	/**
	 * Set fragment data
	 */
	fun setData(dataType: Int, primaryKey: String?) {
		this.dataType = dataType
		this.liveDataType = LiveData.values()[dataType]
		this.primaryKey = primaryKey
	}

}