package net.pokeranalytics.android.ui.fragment

import android.os.Bundle
import android.view.View
import io.realm.Realm
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import net.pokeranalytics.android.calculus.Calculator
import net.pokeranalytics.android.calculus.ComputableGroup
import net.pokeranalytics.android.calculus.Report
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.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.StatRow
import timber.log.Timber
import java.util.*
import kotlin.coroutines.CoroutineContext

class StatisticsFragment : TableReportFragment() {

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

	private var stringAll = ""
	private var stringCashGame = ""
	private var stringTournament = ""

    companion object {

        /**
         * Create new instance
         */
        fun newInstance(report: Report? = null): StatisticsFragment {
            val fragment = StatisticsFragment()
	        report?.let {
		        fragment.report = it
	        }
            val bundle = Bundle()
            fragment.arguments = bundle
            return fragment
        }
    }

    // Life Cycle

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

	override fun sessionsChanged() {
		this.launchStatComputation()
		this.statsAdapter?.notifyDataSetChanged()
	}

	override fun convertReportIntoRepresentables(report: Report): ArrayList<RowRepresentable> {
		val rows: ArrayList<RowRepresentable> = ArrayList()
		report.results.forEach { result ->
			rows.add(CustomizableRowRepresentable(title = result.group.name))
			result.group.stats?.forEach { stat ->
				rows.add(StatRow(stat, result.computedStat(stat), result.group.name))
			}
		}
		return rows
	}


    // Business

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

		GlobalScope.launch(coroutineContext) {

			val test = GlobalScope.async {
				val s = Date()
				Timber.d(">>> start...")

				val realm = Realm.getDefaultInstance()
				report = createSessionGroupsAndStartCompute(realm)
				realm.close()

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

			}
			test.await()

			if (!isDetached) {
				showResults()
			}
		}
	}

	/**
	 * Create session groups and start computations
	 */
	private fun createSessionGroupsAndStartCompute(realm: Realm): Report {

		val allStats: List<Stat> = listOf(
			Stat.NET_RESULT,
			Stat.HOURLY_RATE,
			Stat.AVERAGE,
			Stat.NUMBER_OF_SETS,
			Stat.AVERAGE_HOURLY_DURATION,
			Stat.HOURLY_DURATION
		)
		val allSessionGroup = ComputableGroup(Query(), allStats)

		val cgStats: List<Stat> = listOf(
			Stat.NET_RESULT,
			Stat.HOURLY_RATE,
			Stat.NET_BB_PER_100_HANDS,
			Stat.HOURLY_RATE_BB,
			Stat.AVERAGE,
			Stat.STANDARD_DEVIATION_HOURLY,
			Stat.WIN_RATIO,
			Stat.NUMBER_OF_GAMES,
			Stat.AVERAGE_BUYIN
		)
		val cgSessionGroup = ComputableGroup(Query(QueryCondition.IsCash), cgStats)
		val tStats: List<Stat> =
			listOf(Stat.NET_RESULT, Stat.HOURLY_RATE, Stat.ROI, Stat.WIN_RATIO, Stat.NUMBER_OF_GAMES, Stat.AVERAGE_BUYIN)
		val tSessionGroup = ComputableGroup(Query(QueryCondition.IsTournament), tStats)

		Timber.d(">>>>> Start computations...")

		val options = Calculator.Options()
		val computedStats = mutableListOf<Stat>()
		computedStats.addAll(allStats)
		computedStats.addAll(cgStats)
		computedStats.addAll(tStats)
		options.stats = computedStats

		return Calculator.computeGroups(realm, listOf(allSessionGroup, cgSessionGroup, tSessionGroup), options)
	}

}