package net.pokeranalytics.android.ui.view

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import androidx.appcompat.widget.SwitchCompat
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import androidx.core.widget.ContentLoadingProgressBar
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.row_history_session.view.*
import kotlinx.android.synthetic.main.row_transaction.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.adapter.RowRepresentableAdapter
import net.pokeranalytics.android.ui.extensions.setTextFormat
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.StatDoubleRow
import net.pokeranalytics.android.ui.view.rowrepresentable.StatRow

/**
 * An interface used to factor the configuration of RecyclerView.ViewHolder
 */
interface BindableHolder {
	fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
	}
}

/**
 * Row View Type for recyclerView's adapter
 * [layoutRes] is the resource layout to display
 */
enum class RowViewType(private var layoutRes: Int) {

	// Header
	HEADER_TITLE(R.layout.row_header_title),
	HEADER_TITLE_VALUE(R.layout.row_header_title_value),
	HEADER_TITLE_AMOUNT(R.layout.row_header_title_amount),
	HEADER_TITLE_AMOUNT_BIG(R.layout.row_header_title_amount_big),
	LOCATION_TITLE(R.layout.row_title),
	INFO(R.layout.row_info),

	// Row
	TITLE(R.layout.row_title),
	TITLE_ARROW(R.layout.row_title_arrow),
	TITLE_ICON_ARROW(R.layout.row_title_icon_arrow),
	TITLE_VALUE(R.layout.row_title_value),
	TITLE_VALUE_ARROW(R.layout.row_title_value_arrow),
	TITLE_SWITCH(R.layout.row_title_switch),
	TITLE_GRID(R.layout.row_bottom_sheet_grid_title),
	DATA(R.layout.row_title),
	BOTTOM_SHEET_DATA(R.layout.row_bottom_sheet_title),
	TITLE_CHECK(R.layout.row_title_check),
	TITLE_VALUE_CHECK(R.layout.row_title_value_check),
	LOADER(R.layout.row_loader),

	// Custom row
	ROW_SESSION(R.layout.row_history_session),
	ROW_TRANSACTION(R.layout.row_transaction),
	ROW_BUTTON(R.layout.row_button),
	ROW_FOLLOW_US(R.layout.row_follow_us),
	STATS(R.layout.row_stats_title_value),
	STATS_DOUBLE(R.layout.row_stats_double),
	GRAPH(R.layout.row_graph),

	// Separator
	SEPARATOR(R.layout.row_separator);

	/**
	 * View holder
	 */
	fun viewHolder(parent: ViewGroup): RecyclerView.ViewHolder {

		val layout = LayoutInflater.from(parent.context).inflate(layoutRes, parent, false)

		return when (this) {

			// Row View Holder
			HEADER_TITLE, HEADER_TITLE_VALUE, HEADER_TITLE_AMOUNT, HEADER_TITLE_AMOUNT_BIG,
			LOCATION_TITLE, INFO,
			TITLE, TITLE_ARROW, TITLE_ICON_ARROW, TITLE_VALUE, TITLE_VALUE_ARROW, TITLE_GRID, TITLE_SWITCH, TITLE_CHECK, TITLE_VALUE_CHECK,
			DATA, BOTTOM_SHEET_DATA, LOADER -> RowViewHolder(layout)

			// Row Session
			ROW_SESSION -> RowSessionViewHolder(layout)

			// Row Transaction
			ROW_TRANSACTION -> RowTransactionViewHolder(layout)

			// Row Button
			ROW_BUTTON -> RowButtonViewHolder(layout)

			// Row Follow Us
			ROW_FOLLOW_US -> RowFollowUsViewHolder(layout)

			// Row Stats
			STATS -> StatsTitleValueViewHolder(layout)
			STATS_DOUBLE -> StatsDoubleViewHolder(layout)
			GRAPH -> GraphViewHolder(layout)

			// Separator
			SEPARATOR -> SeparatorViewHolder(layout)

			//else -> throw Exception("Undefined rowViewType's holder")
		}
	}

	/**
	 * Display a generic row (title, value, container)
	 */
	inner class RowViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {


			if (row is CustomizableRowRepresentable) {

				// Customizable Row

				// Title
				itemView.findViewById<AppCompatTextView>(R.id.title)?.let {
					it.text = row.localizedTitle(itemView.context)
				}

				// Value
				itemView.findViewById<AppCompatTextView?>(R.id.value)?.let {
					if (row.computedStat != null) {
						val format = row.computedStat!!.format(itemView.context)
						it.setTextFormat(format, itemView.context)
//						it.setTextColor(format.getColor(itemView.context))
//						it.text = format.text
					} else if (row.value != null) {
						it.text = row.value
					}
				}

				// Listener
				row.isSelectable?.let { isSelectable ->
					if (isSelectable) {
						val listener = View.OnClickListener {
							adapter.delegate?.onRowSelected(position, row)
						}
						itemView.findViewById<View?>(R.id.container)?.let {
							it.setOnClickListener(listener)
						}
					}
				}

			} else {

				// Classic row

				// Title
				itemView.findViewById<AppCompatTextView?>(R.id.title)?.let {
					if (row.resId != null) {
						it.text = row.localizedTitle(itemView.context)
					} else {
						it.text = row.getDisplayName()
					}
				}

				// Value
				itemView.findViewById<AppCompatTextView?>(R.id.value)?.let {
					it.text = adapter.dataSource.stringForRow(row, itemView.context)
				}

				// Icon
				itemView.findViewById<AppCompatImageView>(R.id.icon)?.let { imageView ->
					row.imageRes?.let { imageRes ->
						imageView.setImageResource(imageRes)
					}
				}

				// Listener
				val listener = View.OnClickListener {
					itemView.findViewById<SwitchCompat?>(R.id.switchView)?.let {
						it.isChecked = !it.isChecked
					} ?: run {
						adapter.delegate?.onRowSelected(position, row)
					}
				}

				itemView.findViewById<View?>(R.id.container)?.let {
					it.setOnClickListener(listener)
				}
			}

			// Switch
			itemView.findViewById<SwitchCompat?>(R.id.switchView)?.let {
				it.isChecked = adapter.dataSource.boolForRow(row)
				it.setOnCheckedChangeListener { _, isChecked ->
					adapter.delegate?.onRowValueChanged(isChecked, row)
				}
			}

			// Selected row
			itemView.findViewById<AppCompatImageView?>(R.id.check)?.let {
				it.isSelected = adapter.dataSource.isSelected(row)
			}


		}
	}

	/**
	 * Display a follow us row
	 */
	inner class RowFollowUsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
			itemView.findViewById<AppCompatImageView>(R.id.icon1).setOnClickListener {
				adapter.delegate?.onRowSelected(0, row)
			}
			itemView.findViewById<AppCompatImageView>(R.id.icon2).setOnClickListener {
				adapter.delegate?.onRowSelected(1, row)
			}
			itemView.findViewById<AppCompatImageView>(R.id.icon3).setOnClickListener {
				adapter.delegate?.onRowSelected(2, row)
			}
			itemView.findViewById<AppCompatImageView>(R.id.icon4).setOnClickListener {
				adapter.delegate?.onRowSelected(3, row)
			}
		}
	}

	/**
	 * Display a stat
	 */
	inner class StatsTitleValueViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
		BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {

			// Title
			itemView.findViewById<AppCompatTextView?>(R.id.title)?.text = row.localizedTitle(itemView.context)

			// Value
			itemView.findViewById<AppCompatTextView?>(R.id.value)?.let { view ->
				adapter.dataSource.contentDescriptorForRow(row)?.textFormat?.let {
					view.setTextFormat(it, itemView.context)
				}
			}

			if (row is StatRow) {
				itemView.findViewById<AppCompatImageView?>(R.id.nextArrow)?.isVisible = row.stat.hasEvolutionGraph
			}

			// Listener
			val listener = View.OnClickListener {
				adapter.delegate?.onRowSelected(position, row)
			}
			itemView.findViewById<View?>(R.id.container)?.setOnClickListener(listener)
		}
	}

	/**
	 * Display a stat
	 */
	inner class StatsDoubleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
		BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {


			if (row is StatDoubleRow) {

				// Stat 1
				itemView.findViewById<AppCompatTextView?>(R.id.stat1Name)?.let { view ->
					row.computedStat1?.stat?.resId?.let {
						view.text = view.context.getString(it)
					}
				}

				itemView.findViewById<AppCompatTextView?>(R.id.stat1Value)?.let { view ->
					row.computedStat1?.format(view.context)?.let {
						view.setTextFormat(it, itemView.context)
					}
				}

				// Stat 2
				itemView.findViewById<AppCompatTextView?>(R.id.stat2Name)?.let { view ->
					row.computedStat2?.stat?.resId?.let {
						view.text = view.context.getString(it)
					}
				}

				itemView.findViewById<AppCompatTextView?>(R.id.stat2Value)?.let { view ->
					row.computedStat2?.format(view.context)?.let {
						view.setTextFormat(it, itemView.context)
					}
				}
			}



			// Listener
			val listener = View.OnClickListener {
				adapter.delegate?.onRowSelected(position, row)
			}
			itemView.findViewById<View?>(R.id.container)?.setOnClickListener(listener)
		}
	}


	/**
	 * Display a stat
	 */
	inner class GraphViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView),
		BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {

			//TODO: Implementation

			// Listener
			val listener = View.OnClickListener {
				adapter.delegate?.onRowSelected(position, row)
			}
			itemView.findViewById<View?>(R.id.container)?.setOnClickListener(listener)
		}
	}


	/**
	 * Display a button in a row
	 */
	inner class RowButtonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
			itemView.findViewById<AppCompatTextView>(R.id.title).text = row.localizedTitle(itemView.context)
			itemView.findViewById<AppCompatTextView>(R.id.title).isVisible = !adapter.dataSource.boolForRow(row)
			itemView.findViewById<ContentLoadingProgressBar>(R.id.progressBar).isVisible = adapter.dataSource.boolForRow(row)
			val listener = View.OnClickListener {
				adapter.delegate?.onRowSelected(position, row)
			}
			itemView.findViewById<ConstraintLayout>(R.id.container).setOnClickListener(listener)
		}
	}

	/**
	 * Display a session view
	 */
	inner class RowSessionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
			itemView.sessionRow.setData(row as Session)
			val listener = View.OnClickListener {
				adapter.delegate?.onRowSelected(position, row)
			}
			itemView.sessionRow.setOnClickListener(listener)
		}
	}

	/**
	 * Display a transaction view
	 */
	inner class RowTransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
			itemView.transactionRow.setData(row as Transaction)
			val listener = View.OnClickListener {
				adapter.delegate?.onRowSelected(position, row)
			}
			itemView.transactionRow.setOnClickListener(listener)
		}
	}

	/**
	 * Display a separator
	 */
	inner class SeparatorViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		override fun bind(position: Int, row: RowRepresentable, adapter: RowRepresentableAdapter) {
		}
	}

}