package net.pokeranalytics.android.ui.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.BarLineChartBase
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.highlight.Highlight
import com.github.mikephil.charting.listener.OnChartValueSelectedListener
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_evograph.*
import kotlinx.coroutines.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.ui.activity.components.PokerAnalyticsActivity
import net.pokeranalytics.android.ui.extensions.ChipGroupExtension
import net.pokeranalytics.android.ui.extensions.px
import net.pokeranalytics.android.ui.fragment.components.PokerAnalyticsFragment
import net.pokeranalytics.android.ui.graph.PALineDataSet
import net.pokeranalytics.android.ui.graph.setStyle
import net.pokeranalytics.android.ui.view.LegendView
import timber.log.Timber
import java.text.DateFormat
import java.util.*
import kotlin.coroutines.CoroutineContext

class GraphParameters(var stat: Stat, var computableGroup: ComputableGroup, var report: Report) {

}

class GraphFragment : PokerAnalyticsFragment(), OnChartValueSelectedListener, CoroutineScope {

	private lateinit var parentActivity: PokerAnalyticsActivity

	private var stat: Stat = Stat.NETRESULT
	private var reports: MutableMap<AggregationType, Report> = hashMapOf()
	lateinit private var computableGroup: ComputableGroup

	lateinit private var selectedReport: Report

	lateinit var legendView: LegendView
	lateinit var chartView: BarLineChartBase<*>

	private var aggregationTypes: List<AggregationType> = listOf()

	override val coroutineContext: CoroutineContext
		get() = Dispatchers.Main

	companion object {

	}

	fun setData(stat: Stat, group: ComputableGroup, report: Report) {
		this.stat = stat
		this.computableGroup = group

		this.aggregationTypes = stat.aggregationTypes
		this.reports[this.aggregationTypes.first()] = report
		this.selectedReport = report

	}

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

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

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

		parentActivity = activity as PokerAnalyticsActivity
		parentActivity.title = stat.localizedTitle(requireContext())

		this.legendView = LegendView(requireContext())
		this.legendContainer.addView(this.legendView)

		this.loadGraph(this.selectedReport)

		this.aggregationTypes.forEach { type ->
			val chip = Chip(requireContext())
			chip.id = type.ordinal
			chip.text = requireContext().getString(type.resId)
			chip.chipStartPadding = 8f.px
			chip.chipEndPadding = 8f.px
			this.chipGroup.addView(chip)
		}

		this.chipGroup.check(this.stat.aggregationTypes.first().ordinal)

		this.chipGroup.setOnCheckedChangeListener(object : ChipGroupExtension.SingleSelectionOnCheckedListener() {
			override fun onCheckedChanged(group: ChipGroup, checkedId: Int) {
				super.onCheckedChanged(group, checkedId)
				val aggregationType = aggregationTypes[checkedId]

				reports[aggregationType]?.let {
					loadGraph(it)
				} ?: run {

				}

			}
		})

	}

	private fun launchStatComputation() {

		GlobalScope.launch(coroutineContext) {

			var r: Report? = null
			val test = GlobalScope.async {
				val s = Date()
				Timber.d(">>> start...")

				val realm = Realm.getDefaultInstance()

				val aggregationType = stat.aggregationTypes.first()
				r = Calculator.computeStatsWithEvolutionByAggregationType(realm, computableGroup, aggregationType)

				realm.close()

				val e = Date()
				val duration = (e.time - s.time) / 1000.0
				Timber.d(">>> ended in $duration seconds")

			}
			test.await()

			if (!isDetached) {
				r?.let {
					loadGraph(it)
				}
			}
		}

	}


	fun loadGraph(report: Report) {

		report.results.firstOrNull()?.defaultStatEntries(stat)?.let { entries ->

			this.legendView.prepareWithStat(this.stat, entries.size)

			val dataSet = PALineDataSet(entries, this.stat.name, requireContext())
			val colors = arrayOf(R.color.green_light).toIntArray()
			dataSet.setColors(colors, context)
			dataSet.setDrawCircles(false)
			val lineData = LineData(listOf(dataSet))

			this.chartView = when (stat.graphType) {
				GraphType.LINE -> {
					val lineChart = LineChart(context)
					lineChart.data = lineData
					lineChart
				}
				GraphType.BAR -> {
					val barChart = BarChart(context)
					barChart
				}
			}

			this.chartContainer.addView(this.chartView)

			this.chartView.setStyle(false, requireContext())
			this.chartView.setOnChartValueSelectedListener(this)

			this.chartView.highlightValue((entries.size - 1).toFloat(), 0)
		}

	}

	// OnChartValueSelectedListener

	override fun onNothingSelected() {
		// nothing to do
	}

	override fun onValueSelected(e: Entry?, h: Highlight?) {

		e?.let { entry ->

			val identifier = entry.data as ObjectIdentifier
			val item = getRealm().where(identifier.clazz).equalTo("id", identifier.id).findAll().firstOrNull()
			item?.let {

				val formattedDate = DateFormat.getDateInstance(DateFormat.SHORT).format(it.startDate())
				val entryValue = it.formattedValue(this.stat, requireContext())
				val totalStatValue = this.stat.format(e.y.toDouble(), currency = null, context = requireContext())

				this.legendView.setItemData(this.stat, formattedDate, entryValue, totalStatValue)
			}

		}

	}

}