package net.pokeranalytics.android.ui.fragment

import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.tabs.TabLayout
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_calendar_details.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputedResults
import net.pokeranalytics.android.calculus.Stat
import net.pokeranalytics.android.model.filter.Query
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.activity.ProgressReportActivity
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.view.RowRepresentable
import net.pokeranalytics.android.ui.view.RowViewType
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.GraphRow
import net.pokeranalytics.android.ui.view.rowrepresentable.StatDoubleRow
import timber.log.Timber
import java.util.*
import kotlin.collections.ArrayList

class CalendarDetailsFragment : PokerAnalyticsFragment(), StaticRowRepresentableDataSource, RowRepresentableDelegate {

	companion object {
		fun newInstance(context: Context) {
			val intent = Intent(context, CalendarDetailsFragment::class.java)
			context.startActivity(intent)
		}
	}

	private lateinit var statsAdapter: RowRepresentableAdapter

	private var title: String? = ""
	private var computedResults: ComputedResults? = null
	private var sessionTypeCondition: QueryCondition? = null
	private var rowRepresentables: ArrayList<RowRepresentable> = ArrayList()

	/**
	 * Set data
	 */
	fun setData(computedResults: ComputedResults?, sessionTypeCondition: QueryCondition?, title: String?) {

		this.computedResults = computedResults
		this.sessionTypeCondition = sessionTypeCondition
		this.title = title

		displayData()
		launchStatComputation()

	}

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

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

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

		setDisplayHomeAsUpEnabled(true)

		var tabIndexToSelect = 0
		sessionTypeCondition?.let {
			tabIndexToSelect = when (it) {
				QueryCondition.IsCash -> 1
				QueryCondition.IsTournament -> 2
				else -> 0
			}
		}

		tabs.getTabAt(tabIndexToSelect)?.select()

		tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
			override fun onTabSelected(tab: TabLayout.Tab) {
				when (tab.position) {
					0 -> sessionTypeCondition = null
					1 -> sessionTypeCondition = QueryCondition.IsCash
					2 -> sessionTypeCondition = QueryCondition.IsTournament
				}
				launchStatComputation()
			}

			override fun onTabUnselected(tab: TabLayout.Tab) {
			}

			override fun onTabReselected(tab: TabLayout.Tab) {
			}
		})

		statsAdapter = RowRepresentableAdapter(this, this)

		val viewManager = LinearLayoutManager(requireContext())

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


	}

	/**
	 * Display data
	 */
	private fun displayData() {
		setToolbarTitle(title)
	}

	// StaticRowRepresentableDataSource

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

	override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
		when (row) {
			is GraphRow -> {
				val report = row.report
				val stat = row.stat

				if (report != null && stat != null) {
					val title = row.title ?: stat.localizedTitle(requireContext())
					ProgressReportActivity.newInstance(requireContext(), report, title, stat, false)
				}
			}
		}
	}

	/**
	 * Launch stat computation
	 */
	private fun launchStatComputation() {

		progressBar.isVisible = true
		progressBar.animate().alpha(1f).start()
		recyclerView.animate().alpha(0f).start()

		computedResults?.let { computedResults ->

			GlobalScope.launch {

				val startDate = Date()

				val realm = Realm.getDefaultInstance()

				val query = Query().merge(computedResults.group.query)
				query.remove(QueryCondition.IsCash)
				query.remove(QueryCondition.IsTournament)
				when (sessionTypeCondition) {
					QueryCondition.IsCash -> query.add(QueryCondition.IsCash)
					QueryCondition.IsTournament -> query.add(QueryCondition.IsTournament)
				}

//				val conditions = ArrayList<QueryCondition>().apply {
//					addAll(computedResults.group.conditions)
//
//					// Remove session type _conditions
//					removeAll(Criteria.Cash.queryConditions)
//					removeAll(Criteria.Tournament.queryConditions)
//
//					when (sessionTypeCondition) {
//						QueryCondition.IsCash -> addAll(Criteria.Cash.queryConditions)
//						QueryCondition.IsTournament -> addAll(Criteria.Tournament.queryConditions)
//					}
//				}

				val requiredStats: List<Stat> = listOf(Stat.LOCATIONS_PLAYED, Stat.LONGEST_STREAKS, Stat.DAYS_PLAYED, Stat.STANDARD_DEVIATION_HOURLY)
				val options = Calculator.Options(
					progressValues = Calculator.Options.ProgressValues.STANDARD,
					stats = requiredStats,
					query = query
				)
				val report = Calculator.computeStats(realm, options)

				Timber.d("Report take: ${System.currentTimeMillis() - startDate.time}ms")

				report.results.firstOrNull()?.let {

					// Create rows
					val dataSet1 = report.results.firstOrNull()?.defaultStatEntries(Stat.NET_RESULT, requireContext())
					val dataSet2 = report.results.firstOrNull()?.defaultStatEntries(Stat.STANDARD_DEVIATION, requireContext())
					val dataSet3 = report.results.firstOrNull()?.defaultStatEntries(Stat.HOURLY_DURATION, requireContext())

					rowRepresentables.clear()
					rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.net_result))
					rowRepresentables.add(GraphRow(dataSet1, report = report, stat = Stat.NET_RESULT))
					rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.NET_RESULT), it.computedStat(Stat.HOURLY_RATE)))
					rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.LOCATIONS_PLAYED), it.computedStat(Stat.LONGEST_STREAKS)))
					rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.distribution))
					rowRepresentables.add(
						GraphRow(
							dataSet2,
							requireContext().getString(R.string.distribution),
							report = report,
							stat = Stat.STANDARD_DEVIATION
						)
					)
					rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.WIN_RATIO), it.computedStat(Stat.MAXIMUM_NETRESULT)))
					rowRepresentables.add(CustomizableRowRepresentable(RowViewType.HEADER_TITLE, resId = R.string.volume))
					rowRepresentables.add(GraphRow(dataSet3, report = report, stat = Stat.HOURLY_DURATION))
					rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.HOURLY_DURATION), it.computedStat(Stat.AVERAGE_HOURLY_DURATION)))
					rowRepresentables.add(StatDoubleRow(it.computedStat(Stat.DAYS_PLAYED), it.computedStat(Stat.MAXIMUM_DURATION)))
				}


				launch(Dispatchers.Main) {
					statsAdapter.notifyDataSetChanged()
					progressBar.animate().cancel()
					progressBar.animate().alpha(0f).withEndAction { progressBar.isVisible = false }.start()
					recyclerView.animate().cancel()
					recyclerView.animate().alpha(1f).start()
				}
			}
		}
	}

}