package net.pokeranalytics.android.ui.adapter

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.AppCompatTextView
import androidx.recyclerview.widget.RecyclerView
import io.realm.RealmResults
import kotlinx.android.synthetic.main.row_feed_session.view.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.ui.view.BindableHolder
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.extensions.getMonthAndYear
import timber.log.Timber
import java.util.*
import kotlin.collections.HashMap


/**
 * An adapter capable of displaying a list of RowRepresentables
 * @param dataSource the datasource providing rows
 * @param delegate the delegate, notified of UI actions
 */
class FeedSessionRowRepresentableAdapter(
	var delegate: RowRepresentableDelegate? = null,
	var realmResults: RealmResults<Session>,
	var pendingRealmResults: RealmResults<Session>,
	var distinctHeaders: RealmResults<Session>
) :
	RecyclerView.Adapter<RecyclerView.ViewHolder>() {

	private var headersPositions = HashMap<Int, Date?>()
	private lateinit var sortedHeaders: SortedMap<Int, Date?>

	init {
		refreshData()
	}

	/**
	 * Display a session view
	 */
	inner class RowSessionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		fun bind(position: Int, row: Session?, adapter: FeedSessionRowRepresentableAdapter) {

			itemView.sessionRow.setData(row as Session)
			val listener = View.OnClickListener {
				adapter.delegate?.onRowSelected(position, row)
			}
			itemView.sessionRow.setOnClickListener(listener)
		}
	}

	/**
	 * Display a session view
	 */
	inner class HeaderTitleViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), BindableHolder {
		fun bind(title: String) {
			// Title
			itemView.findViewById<AppCompatTextView>(R.id.title)?.let {
				it.text = title
			}
		}
	}

	override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
		return if (viewType == RowViewType.ROW_SESSION.ordinal) {
			val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_feed_session, parent, false)
			RowSessionViewHolder(layout)
		} else {
			val layout = LayoutInflater.from(parent.context).inflate(R.layout.row_header_title, parent, false)
			HeaderTitleViewHolder(layout)
		}

	}

	override fun getItemViewType(position: Int): Int {
		if (sortedHeaders.containsKey(position)) {
			return RowViewType.HEADER_TITLE.ordinal
		} else {
			return RowViewType.ROW_SESSION.ordinal
		}
	}

	override fun getItemCount(): Int {
		return realmResults.size + pendingRealmResults.size + distinctHeaders.size
	}

	override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
		if (holder is RowSessionViewHolder) {
			holder.bind(position, getSessionForPosition(position), this)
		} else if (holder is HeaderTitleViewHolder) {
			holder.bind(getHeaderForPosition(holder.itemView.context, position))
		}
	}

	/**
	 * Return the header
	 */
	private fun getHeaderForPosition(context: Context, position :Int) : String {
		if (sortedHeaders.containsKey(position)) {

			// If the header has no date, it's a pending session
			return if (sortedHeaders[position] == null) {
				context.getString(R.string.pending)
			} else {
				// Else, return the formatted date
				val realmHeaderPosition = if (pendingRealmResults.size > 0) sortedHeaders.keys.indexOf(position) - 1 else sortedHeaders.keys.indexOf(position)
				distinctHeaders[realmHeaderPosition]?.startDate?.getMonthAndYear() ?: ""
			}
		}
		return NULL_TEXT
	}

	/**
	 * Get real index
	 */
	private fun getSessionForPosition(position: Int): Session? {
		return if (pendingRealmResults.size > 0 && position < pendingRealmResults.size + 1) {
			// If we have pending session & the position is between these sessions
			 pendingRealmResults[position - 1]
		} else {
			// Else, return the correct session

			// Row position
			var headersBefore = 0
			for (key in sortedHeaders.keys) {
				if (position > key) {
					headersBefore++
				} else {
					break
				}
			}

			realmResults[position - headersBefore - pendingRealmResults.size]
		}
	}

	/**
	 * Refresh headers positions
	 */
	fun refreshData() {

		headersPositions.clear()

		// If we have pending sessions, set the first header to null
		if (pendingRealmResults.size > 0) {
			headersPositions[0] = null
		}

		val start = System.currentTimeMillis()

		var previousYear = Int.MAX_VALUE
		var previousMonth = Int.MAX_VALUE

		val calendar = Calendar.getInstance()

		// Add headers if the date doesn't exist yet
		for ((index, session) in realmResults.withIndex()) {
			calendar.time = session.startDate ?: session.creationDate
			if (checkHeaderCondition(calendar, previousYear, previousMonth)) {
				headersPositions[index + headersPositions.size + pendingRealmResults.size] = session.startDate ?: session.creationDate
				previousYear = calendar.get(Calendar.YEAR)
				previousMonth = calendar.get(Calendar.MONTH)
			}
		}

		sortedHeaders = headersPositions.toSortedMap()

		Timber.d("Create viewTypesPositions in: ${System.currentTimeMillis() - start}ms")
	}

	/**
	 * Check if we need to add a header
	 * Can be change to manage different condition
	 */
	private fun checkHeaderCondition(currentCalendar: Calendar, previousYear: Int, previousMonth: Int) : Boolean {
		return currentCalendar.get(Calendar.YEAR) == previousYear && currentCalendar.get(Calendar.MONTH) < previousMonth || (currentCalendar.get(Calendar.YEAR) < previousYear)

	}


}