package net.pokeranalytics.android.ui.fragment

import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.Menu
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.fragment_filter_details.*
import kotlinx.android.synthetic.main.fragment_filter_details.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.ui.activity.FilterDetailsActivity
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
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.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.fragment.components.bottomsheet.BottomSheetFragment
import net.pokeranalytics.android.ui.helpers.DateTimePickerManager
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterCategoryRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterSectionRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.shortDate
import net.pokeranalytics.android.util.extensions.shortTime
import net.pokeranalytics.android.util.extensions.toMinutes
import timber.log.Timber
import java.util.*
import kotlin.collections.ArrayList

open class  FilterDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {

	lateinit var parentActivity: PokerAnalyticsActivity
	lateinit var rowRepresentableAdapter: RowRepresentableAdapter

	private var currentFilter: Filter? = null
	private var rows: ArrayList<RowRepresentable> = ArrayList()
	private var rowsForFilterSubcategoryRow: HashMap<FilterSectionRow, ArrayList<RowRepresentable>> = HashMap()

	private var primaryKey: String? = null
	private var filterMenu: Menu? = null
	private var filterCategoryRow: FilterCategoryRow? = null
	private val selectedRows = ArrayList<FilterElementRow>()
	private var isUpdating = false
	private var shouldOpenKeyboard = true

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

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

	override fun onBackPressed() {
		super.onBackPressed()
		saveData()
	}

	override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
		super.onRowSelected(position, row, fromAction)

		Timber.d("Row: $row")

		when (row) {
			is FilterElementRow.DateFilterElementRow -> DateTimePickerManager.create(requireContext(), row, this, row.dateValue, onlyDate = !row.showTime, onlyTime = row.showTime)
			is FilterElementRow.PastDays -> {
				val pastDays = if (row.lastDays > 0) row.lastDays.toString() else ""
				val data = row.editingDescriptors(mapOf("pastDays" to pastDays))
				BottomSheetFragment.create(fragmentManager, row, this, data, true)
			}
			is FilterElementRow.LastGames -> {
				val lastGames = if (row.lastGames > 0) row.lastGames.toString() else ""
				val data = row.editingDescriptors(mapOf("lastGames" to lastGames))
				BottomSheetFragment.create(fragmentManager, row, this, data, true)
			}
			is FilterElementRow.LastSessions -> {
				val lastSessions = if (row.lastSessions > 0) row.lastSessions.toString() else ""
				val data = row.editingDescriptors(mapOf("lastSessions" to lastSessions))
				BottomSheetFragment.create(fragmentManager, row, this, data, true)
			}
			is FilterElementRow.DurationFilterElement -> {
				val hours = if (row.minutes / 60 > 0) (row.minutes / 60).toString() else ""
				val minutes = if (row.minutes % 60 > 0) (row.minutes % 60).toString() else ""
				val data = row.editingDescriptors(mapOf("hours" to hours, "minutes" to minutes))
				BottomSheetFragment.create(fragmentManager, row, this, data, true)
			}
			is FilterElementRow.AmountFilterElement -> {
				val amount = if (row.amount > 0) row.amount.toString() else ""
				val data = row.editingDescriptors(mapOf("amount" to amount))
				BottomSheetFragment.create(fragmentManager, row, this, data, true)
			}
			else -> {
				updateRowsSelection(row)
			}
		}
	}

	override fun stringForRow(row: RowRepresentable): String {
		return when (row) {
			is FilterElementRow.PastDays -> if (row.lastDays > 0) row.lastDays.toString() else NULL_TEXT
			is FilterElementRow.LastGames -> if (row.lastGames > 0) row.lastGames.toString() else NULL_TEXT
			is FilterElementRow.LastSessions -> if (row.lastSessions > 0) row.lastSessions.toString() else NULL_TEXT
			is FilterElementRow.DateFilterElementRow -> if (row.showTime) row.dateValue.shortTime() else row.dateValue.shortDate()
			is FilterElementRow.AmountFilterElement -> if (row.amount > 0) row.amount.toString() else NULL_TEXT
			is FilterElementRow.DurationFilterElement -> row.minutes.toMinutes(requireContext())
			else -> super.stringForRow(row)
		}
	}

	override fun isSelected(row: RowRepresentable): Boolean {
		return selectedRows.contains(row)
	}

	override fun onRowValueChanged(value: Any?, row: RowRepresentable) {
		super.onRowValueChanged(value, row)
		Timber.d("onRowValueChanged: $row $value")

		when (row) {
			is FilterElementRow.DateFilterElementRow -> row.dateValue = if (value != null && value is Date) value else Date()
			is FilterElementRow.PastDays -> row.lastDays = if (value != null && value is String) value.toInt() else 0
			is FilterElementRow.LastGames -> row.lastGames = if (value != null && value is String) value.toInt() else 0
			is FilterElementRow.LastSessions -> row.lastSessions = if (value != null && value is String) value.toInt() else 0
			is FilterElementRow.AmountFilterElement -> row.amount = if (value != null && value is String) value.toDouble() else 0.0
			is FilterElementRow.DurationFilterElement -> {
				if (value is ArrayList<*>) {
					val hours = try {
						(value[0] as String? ?: "0").toInt()
					} catch (e: Exception) {
						0
					}
					val minutes = try {
						(value[1] as String? ?: "0").toInt()
					} catch (e: Exception) {
						0
					}

					row.minutes = hours * 60 + minutes
				} else {
					row.minutes = 0
				}
			}
		}

		// Remove the row before updating the selected rows list
		selectedRows.remove(row as FilterElementRow)
		updateRowsSelection(row, value == null)

	}

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

	override fun viewTypeForPosition(position: Int): Int {
		val rowViewType = rowRepresentableForPosition(position)?.viewType ?: -1
		return if (rowViewType != -1) rowViewType else RowViewType.TITLE_CHECK.ordinal
	}

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

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

		val viewManager = LinearLayoutManager(requireContext())

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

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

		primaryKey?.let {
			currentFilter = Filter.getFilterBydId(getRealm(), it)
		}

		filterCategoryRow?.let {

			this.appBar.toolbar.title = it.localizedTitle(requireContext())

			this.rows.clear()
			this.rowsForFilterSubcategoryRow.clear()
			this.rows.addAll(it.filterElements)

			this.rows.forEach { element ->
				if (element is FilterElementRow && currentFilter?.contains(element) == true) {
					currentFilter?.setSavedValueForElement(element)
					this.selectedRows.add(element)
				}
			}

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

	/**
	 * Update rows selection
	 */
	private fun updateRowsSelection(row: RowRepresentable, forceDeselection: Boolean = false) {

		if (selectedRows.contains(row) || forceDeselection) {
			selectedRows.remove(row)
		} else {
			if (row is FilterElementRow) {
				row.sectionToExclude?.let { filterSectionToExclude ->
					val excludedFilters = selectedRows.filter {
						filterSectionToExclude.contains(it.filterSectionRow)
					}
					excludedFilters.forEach {
						selectedRows.remove(it)
						rowRepresentableAdapter.refreshRow(it)
					}
				}
				selectedRows.add(row)
			}
		}

		// Update UI
		rowRepresentableAdapter.refreshRow(row)
	}

	/**
	 * Save data
	 */
	private fun saveData() {
		//TODO: Save currentFilter details data
		Timber.d("Save data for filter: ${currentFilter?.id}")
		selectedRows.forEach {
			Timber.d("Selected rows: $it")
		}

		val realm = getRealm()
		realm.beginTransaction()
		currentFilter?.createOrUpdateFilterConditions(selectedRows)
		realm.commitTransaction()

		currentFilter?.filterConditions?.forEach {
			Timber.d("Condition: $it")
		}


		finishActivityWithResult(currentFilter?.id)
	}


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

	/**
	 * Set fragment data
	 */
	fun setData(primaryKey: String, filterCategory: Int) {
		this.primaryKey = primaryKey
		this.filterCategoryRow = FilterCategoryRow.values()[filterCategory]
	}

}