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.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.chip.Chip
import kotlinx.android.synthetic.main.fragment_editable_data.appBar
import kotlinx.android.synthetic.main.fragment_editable_data.recyclerView
import kotlinx.android.synthetic.main.fragment_filters.*
import kotlinx.android.synthetic.main.fragment_filters.view.toolbar
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.ui.activity.FilterDetailsActivity
import net.pokeranalytics.android.ui.activity.FiltersActivity
import net.pokeranalytics.android.ui.activity.FiltersListActivity
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.adapter.StaticRowRepresentableDataSource
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.fragment.components.RealmFragment
import net.pokeranalytics.android.ui.interfaces.FilterActivityRequestCode
import net.pokeranalytics.android.ui.interfaces.FilterableType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.util.Preferences
import net.pokeranalytics.android.util.extensions.sorted
import timber.log.Timber


open class FiltersFragment : RealmFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {

	companion object {
		const val REQUEST_CODE_FILTER_DETAILS = 100
		const val MOST_USED_FILTERS_DISPLAYED = 6

		var currentFilter: Filter? = null

	}

	private lateinit var rowRepresentableAdapter: RowRepresentableAdapter

	private var filterCopy: Filter? = null

	private var rows: ArrayList<RowRepresentable> = ArrayList()
	private var filterMenu: Menu? = null
	private var primaryKey: String? = null
	private lateinit var filterableType: FilterableType

	private var selectedRow: RowRepresentable? = null
	private var isUpdating = false
	private var showMostUsedFiltersLayout = true

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

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

	override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
		super.onActivityResult(requestCode, resultCode, data)

		if (requestCode == REQUEST_CODE_FILTER_DETAILS && resultCode == RESULT_OK) {

			// Update object
			/*
			currentFilter?.id?.let { currentFilterId ->
				Filter.getFilterBydId(getRealm(), currentFilterId)?.let { filter ->
					currentFilter = filter
				}
			}
			*/

			selectedRow?.let {
				rowRepresentableAdapter.refreshRow(it)
			}
		} else if (requestCode == FilterActivityRequestCode.SELECT_FILTER.ordinal) {

			updateMostUsedFilters()

			if (resultCode == RESULT_OK && data != null && data.hasExtra(FiltersActivity.IntentKey.FILTER_ID.keyName)) {
				val filterId = data.getStringExtra(FiltersActivity.IntentKey.FILTER_ID.keyName)
				finishActivityWithResult(filterId)
			}
		}
	}

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

	override fun onBackPressed() {
		if (isUpdating) {
			cancelUpdates()
		} else {
			activity?.finish()
		}
	}

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

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

	override fun stringForRow(row: RowRepresentable): String {
		// Return the number of selected filters for this category
		var selectedFilters = ""
		if (row is FilterCategoryRow) {
			currentFilter?.countBy(row)?.let { nbFilters ->
				if (nbFilters > 0) {
					selectedFilters = nbFilters.toString()
				}
			}
		}
		return selectedFilters
	}

	override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
		super.onRowSelected(position, row, fromAction)
		selectedRow = row
		currentFilter?.id?.let { filterId ->
			FilterDetailsActivity.newInstanceForResult(this, filterId, (row as FilterCategoryRow).ordinal, REQUEST_CODE_FILTER_DETAILS)
		}
	}

	/**
	 * Init UI
	 */
	private fun initUI() {

		setDisplayHomeAsUpEnabled(true)

		this.appBar.toolbar.title = getString(R.string.filter)

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

		moreFilters.setOnClickListener {
            LiveData.FILTER.subType = filterableType.uniqueIdentifier
			FiltersListActivity.newSelectInstance(this, LiveData.FILTER.ordinal, false)
		}

		mostUsedFiltersLayout.isVisible = showMostUsedFiltersLayout
	}

	/**
	 * Init data
	 */
	private fun initData() {

		val realm = getRealm()

		primaryKey?.let {
			currentFilter = realm.copyFromRealm(Filter.getFilterBydId(realm, it))
			isUpdating = true
		} ?: run {
			currentFilter = Filter.newInstance(this.filterableType.uniqueIdentifier) //realm.copyFromRealm(Filter.newInstanceForResult(realm, this.filterableType.ordinal))
		}

		// Create a copy if the user cancels the updates
		currentFilter?.let {
			if (it.isValid && it.isManaged) {
				filterCopy = getRealm().copyFromRealm(it)
			}
		}

		rows.clear()
		rows.addAll(FilterCategoryRow.values(this.filterableType))

		this.rowRepresentableAdapter = RowRepresentableAdapter(this, this)
		this.recyclerView.adapter = rowRepresentableAdapter

	}

	/**
	 * Update the most used filters chips
	 */
	private fun updateMostUsedFilters() {

		var nbChips = 0
		val filters = getRealm().sorted(Filter::class.java, editableOnly = false, filterableTypeUniqueIdentifier = this.filterableType.uniqueIdentifier)
		val currentFilterId = Preferences.getActiveFilterId(requireContext())

		if (isUpdating || filters.isEmpty() || (filters.size == 1 && filters.first()?.id == currentFilterId)) {
			mostUsedFiltersLayout.visibility = View.GONE
			return
		}

		mostUsedFilters.removeAllViews()

		filters.forEach { filter ->
			if (nbChips < MOST_USED_FILTERS_DISPLAYED) {

				if (filter.id != currentFilterId) {
					val chip = Chip(requireContext())
					chip.id = View.generateViewId()
					chip.tag = filter.id
					chip.text = filter.getDisplayName(requireContext())
					chip.chipStartPadding = 8f.px
					chip.chipEndPadding = 8f.px

					chip.isChecked = filter.id == currentFilterId
					chip.setOnCloseIconClickListener {
						chip.isChecked = false
					}
					chip.setOnClickListener {
						if (chip.isChecked) {
							finishActivityWithResult(filter.id)
						} else {
							finishActivityWithResult("")
						}
					}
					mostUsedFilters.addView(chip)
					nbChips++
				}
			}
		}
	}

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

	/**
	 * Validate the  updates of the queryWith
	 */
	private fun validateUpdates() {
		val realm = getRealm()
		realm.beginTransaction()
		currentFilter?.let {
			it.name = it.query.getName(requireContext())
			realm.copyToRealmOrUpdate(it)
		}
		realm.commitTransaction()

		val filterId = currentFilter?.id ?: ""
		finishActivityWithResult(filterId)
	}

	/**
	 * Cancel the latest updates of the queryWith
	 */
	private fun cancelUpdates() {
		val filterId = filterCopy?.id ?: ""
		val realm = getRealm()
		realm.beginTransaction()
		filterCopy?.let {
			realm.copyToRealmOrUpdate(it)
		}
		realm.commitTransaction()
		finishActivityWithResult(filterId)
	}

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

	/**
	 * Set fragment data
	 */
	fun setData(primaryKey: String?, filterableType: FilterableType) {
		this.primaryKey = primaryKey
		this.filterableType = filterableType
	}

	/**
	 * Update the most used filters visibility
	 */
	fun updateMostUsedFiltersVisibility(visible: Boolean) {
		Timber.d("updateMostUsedFiltersVisibility: $visible")
		showMostUsedFiltersLayout = visible
		mostUsedFiltersLayout?.isVisible = visible
	}

}