package net.pokeranalytics.android.ui.fragment.report

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.LinearLayoutManager
import io.realm.Realm
import kotlinx.android.synthetic.main.fragment_composable_table_report.*
import kotlinx.coroutines.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.calculus.*
import net.pokeranalytics.android.model.realm.ComputableResult
import net.pokeranalytics.android.ui.activity.components.ReportActivity
import net.pokeranalytics.android.ui.adapter.DisplayDescriptor
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.RealmFragment
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.CustomizableRowRepresentable
import net.pokeranalytics.android.ui.view.rowrepresentable.StatRow
import net.pokeranalytics.android.util.NULL_TEXT
import net.pokeranalytics.android.util.TextFormat
import timber.log.Timber
import java.util.*
import kotlin.coroutines.CoroutineContext

open class ComposableTableReportFragment : RealmFragment(), StaticRowRepresentableDataSource, CoroutineScope,
	RowRepresentableDelegate {

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

	private var rowRepresentables: ArrayList<RowRepresentable> = ArrayList()

	var statsAdapter: RowRepresentableAdapter? = null
	var report: Report? = null

	companion object {

		/**
		 * Create new instance
		 */
		fun newInstance(report: Report? = null): ComposableTableReportFragment {
			val fragment = ComposableTableReportFragment()
			fragment.report = report

			val bundle = Bundle()
			fragment.arguments = bundle
			return fragment
		}
	}

	// Life Cycle

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

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

		report?.let {
			showResults()
		}
	}

	// Row Representable DS

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

	override fun contentDescriptorForRow(row: RowRepresentable): DisplayDescriptor? {
		val dc = DisplayDescriptor()
		dc.textFormat = TextFormat(NULL_TEXT)
		if (row is StatRow) {
			context?.let { _ ->
				row.computedStat?.let {
					dc.textFormat = it.format()
				}
			}
		}
		return dc
	}

	override fun statFormatForRow(row: RowRepresentable): TextFormat {
		if (row is StatRow) {
			context?.let { _ ->
				row.computedStat?.let { return it.format() }
			}
		}
		return TextFormat(NULL_TEXT)
	}

	override fun onResume() {
		super.onResume()
		statsAdapter?.notifyDataSetChanged()
	}

	// Business

	/**
	 * Init data
	 */
	open fun initData() {
		this.statsAdapter = RowRepresentableAdapter(this, this)
	}

	/**
	 * Init UI
	 */
	open fun initUI() {
		val viewManager = LinearLayoutManager(requireContext())

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

	}

	/**
	 * Show results
	 */
	fun showResults() {
		report?.let {
			this.rowRepresentables = this.convertReportIntoRepresentables(it)
			statsAdapter?.notifyDataSetChanged()
		}
	}

	open fun convertReportIntoRepresentables(report: Report): ArrayList<RowRepresentable> {

		val rows: ArrayList<RowRepresentable> = ArrayList()
		report.results.forEach { result ->
			val title = result.group.query.getName(requireContext()).capitalize()
			rows.add(CustomizableRowRepresentable(title = title))
			val statList = result.group.stats ?: report.options.stats
			statList.forEach { stat ->
				rows.add(StatRow(stat, result.computedStat(stat), result.group.query.getName(requireContext())))
			}
		}
		return rows

//		val rows: ArrayList<RowRepresentable> = ArrayList()
//		report.options.stats.forEach {stat ->
//			rows.add(CustomizableRowRepresentable(title = stat.localizedTitle(requireContext())))
//			report.results.forEach {
//				val title = it.group.name
//				rows.add(StatRow(stat, it.computedStat(stat), it.group.name, title))
//			}
//		}
//		return rows
	}

	// RowRepresentableDelegate

	override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {

		val cr = getRealm().where(ComputableResult::class.java).findAll()
		if (cr.size < 2) {
			Toast.makeText(context, R.string.less_then_2_values_for_display, Toast.LENGTH_LONG).show()
			return
		}

		if (row is StatRow && row.stat.hasProgressGraph) {

			// queryWith groups
			val groupResults = this.report?.results?.filter {
				row.groupName == it.group.query.getName(requireContext())
			}

			groupResults?.firstOrNull()?.let {
				this.launchStatComputationWithEvolution(row.stat, it.group)
			}
		}

	}

	private fun launchStatComputationWithEvolution(stat: Stat, computableGroup: ComputableGroup) {

		showLoader()

		GlobalScope.launch(coroutineContext) {

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

				val realm = Realm.getDefaultInstance()

				val aggregationType = stat.aggregationTypes.first()
				report =
					Calculator.computeStatsWithEvolutionByAggregationType(realm, stat, 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) {
				hideLoader()
				report?.let {
					val title = stat.localizedTitle(requireContext())

					ReportActivity.newInstance(requireContext(), it, title, stat)

//					ProgressReportActivity.newInstanceForResult(requireContext(), stat, it, title = title)
				}
			}
		}
	}

}