package net.pokeranalytics.android.ui.fragment

import android.app.Activity.RESULT_OK
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.app.ActivityOptionsCompat
import androidx.core.view.isVisible
import androidx.interpolator.view.animation.FastOutSlowInInterpolator
import com.google.android.material.tabs.TabLayout
import io.realm.RealmModel
import io.realm.RealmResults
import io.realm.Sort
import io.realm.kotlin.where
import kotlinx.android.synthetic.main.fragment_feed.*
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.LiveData
import net.pokeranalytics.android.model.interfaces.Editable
import net.pokeranalytics.android.model.realm.Filter
import net.pokeranalytics.android.model.realm.Session
import net.pokeranalytics.android.model.realm.Transaction
import net.pokeranalytics.android.ui.activity.*
import net.pokeranalytics.android.ui.activity.components.RequestCode
import net.pokeranalytics.android.ui.adapter.FeedSessionRowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.FeedTransactionRowRepresentableAdapter
import net.pokeranalytics.android.ui.adapter.RowRepresentableDelegate
import net.pokeranalytics.android.ui.fragment.components.FilterableFragment
import net.pokeranalytics.android.ui.interfaces.FilterActivityRequestCode
import net.pokeranalytics.android.ui.interfaces.FilterableType
import net.pokeranalytics.android.ui.view.RowRepresentable
import net.pokeranalytics.android.ui.view.SmoothScrollLinearLayoutManager
import net.pokeranalytics.android.util.Preferences
import java.text.SimpleDateFormat
import java.util.*


class FeedFragment : FilterableFragment(), RowRepresentableDelegate {

	private enum class Tab {
		SESSIONS,
		TRANSACTIONS
	}

	companion object {

		const val REQUEST_CODE_MENU = 100
		const val REQUEST_CODE_TRANSACTION_DETAILS = 101

		fun newInstance(): FeedFragment {
			val fragment = FeedFragment()
			val bundle = Bundle()
			fragment.arguments = bundle
			return fragment
		}
	}

	private lateinit var feedSessionAdapter: FeedSessionRowRepresentableAdapter
	private lateinit var feedTransactionAdapter: FeedTransactionRowRepresentableAdapter
	private lateinit var realmSessions: RealmResults<Session>
	private lateinit var realmTransactions: RealmResults<Transaction>
	private lateinit var betaLimitDate: Date

	private var newSessionCreated: Boolean = false
	private var adapterHasBeenSet: Boolean = false
	private var selectedTransaction: Transaction? = null
	private var selectedTransactionPosition: Int = -1

	override val observedEntities: List<Class<out RealmModel>> = listOf(Session::class.java, Transaction::class.java)

	override fun entitiesChanged(clazz: Class<out RealmModel>) {
		super.entitiesChanged(clazz)

		when (clazz.kotlin) {
			Session::class -> {
				this.feedSessionAdapter.refreshData()
				this.feedSessionAdapter.notifyDataSetChanged()
			}
			Transaction::class -> {
				this.feedTransactionAdapter.refreshData()
				this.feedTransactionAdapter.notifyDataSetChanged()
			}
		}

	}

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

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

	override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
		super.onActivityResult(requestCode, resultCode, data)
		if (requestCode == REQUEST_CODE_MENU && resultCode == RESULT_OK && data != null) {
			when (data.getIntExtra(NewDataMenuActivity.IntentKey.CHOICE.keyName, -1)) {
				0 -> createNewSession(false)
				1 -> createNewSession(true)
				2 -> createNewTransaction()
			}
		} else if (requestCode == REQUEST_CODE_TRANSACTION_DETAILS && resultCode == RESULT_OK && data != null) {
			if (data.getStringExtra(DataListActivity.IntentKey.ITEM_DELETED.keyName) != null) {
				deleteSelectedTransaction()
			}
		} else if (requestCode == FilterActivityRequestCode.CREATE_FILTER.ordinal && resultCode == RESULT_OK) {
			data?.let {
				this.saveFilter(this.requireContext(), it.getStringExtra(FiltersActivity.IntentKey.FILTER_ID.keyName))
			}
		} else if (requestCode == RequestCode.NEW_TRANSACTION.value && resultCode == RESULT_OK) {
			this.selectTab(Tab.TRANSACTIONS)
		} else if (requestCode == RequestCode.NEW_SESSION.value && resultCode == RESULT_OK) {
			this.selectTab(Tab.SESSIONS)
		}

	}

	override fun onDestroyView() {
		super.onDestroyView()
		realmSessions.removeAllChangeListeners()
		realmTransactions.removeAllChangeListeners()
	}

	/*
    override fun setUserVisibleHint(isVisibleToUser: Boolean) {
        super.setUserVisibleHint(isVisibleToUser)
        if (isVisibleToUser && view != null) {
            if (FilterHandler.filterWasUpdated) {
	            applyFilter()
                FilterHandler.filterWasUpdated = false
            }
        }
    }
    */

	override fun onRowSelected(position: Int, row: RowRepresentable, fromAction: Boolean) {
		when (row) {
			is Session -> SessionActivity.newInstance(requireContext(), sessionId = (row as Editable).id)
			is Transaction -> {
				selectedTransaction = row
				selectedTransactionPosition = position
				EditableDataActivity.newInstanceForResult(
					this,
					LiveData.TRANSACTION,
					row.id,
					REQUEST_CODE_TRANSACTION_DETAILS
				)
			}
		}
	}

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

		disclaimerContainer.isVisible = Preferences.shouldShowDisclaimer(requireContext())

		disclaimerDismiss.setOnClickListener {
			Preferences.setStopShowingDisclaimer(requireContext())

			disclaimerContainer.animate().translationY(disclaimerContainer.height.toFloat())
				.setInterpolator(FastOutSlowInInterpolator())
				.withEndAction { disclaimerContainer?.isVisible = false }
				.start()
		}

		addButton.setOnClickListener {
			activity?.let {
				val options = ActivityOptionsCompat.makeSceneTransitionAnimation(it)
				val intent = Intent(requireContext(), NewDataMenuActivity::class.java)
				startActivityForResult(intent, REQUEST_CODE_MENU, options.toBundle())
			}
		}

		tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
			override fun onTabSelected(tab: TabLayout.Tab) {
				when (tab.position) {
					0 -> {
						currentFilterable = FilterableType.SESSION
						recyclerView.adapter = feedSessionAdapter
					}
					1 -> {
						currentFilterable = FilterableType.TRANSACTION
						recyclerView.adapter = feedTransactionAdapter
					}
				}
			}

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

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

	}

	/**
	 * Init data
	 */
	private fun initData() {

		val sdf = SimpleDateFormat("dd/M/yyyy hh:mm", Locale.getDefault())
		betaLimitDate = sdf.parse("17/7/2019 10:00")
        this.currentFilterable = FilterableType.SESSION

		val viewManager = SmoothScrollLinearLayoutManager(requireContext())
		recyclerView.apply {
			setHasFixedSize(true)
			layoutManager = viewManager
		}

		applyFilter()
	}

	private fun loadSessions(filter: Filter? = null) {
		val sessionFilter: Filter? = filter?.let {
			if (it.filterableType == FilterableType.SESSION) {
				it
			} else {
				null
			}
		}

		// Sessions
		this.realmSessions =
			sessionFilter?.results() ?: run { getRealm().where<Session>().isNotNull("startDate").findAll() }
		this.realmSessions = this.realmSessions.sort("startDate", Sort.DESCENDING)

		val pendingSessions = sessionFilter?.let {
			getRealm().where<Session>().alwaysFalse().findAll()
		} ?: run {
			getRealm().where<Session>().isNull("year").isNull("month").findAll().sort("startDate", Sort.DESCENDING)
		}
		var distinctDateSessions = sessionFilter?.results("year", "month") ?: run {
			getRealm().where<Session>().distinct("year", "month").findAll()
		}
		distinctDateSessions = distinctDateSessions.sort("startDate", Sort.DESCENDING)
		this.feedSessionAdapter =
			FeedSessionRowRepresentableAdapter(this, realmSessions, pendingSessions, distinctDateSessions)
	}

	private fun loadTransactions(filter: Filter? = null) {
		val transactionFilter: Filter? = filter?.let {
			if (it.filterableType == FilterableType.TRANSACTION) {
				it
			} else {
				null
			}
		}

		// Transactions
		this.realmTransactions = transactionFilter?.results() ?: run { getRealm().where<Transaction>().findAll() }
		this.realmTransactions = this.realmTransactions.sort("date", Sort.DESCENDING)

		var distinctDateTransactions = transactionFilter?.results("year", "month") ?: run {
			getRealm().where<Transaction>().distinct("year", "month").findAll()
		}
		distinctDateTransactions = distinctDateTransactions.sort("date", Sort.DESCENDING)
		this.feedTransactionAdapter =
			FeedTransactionRowRepresentableAdapter(this, realmTransactions, distinctDateTransactions)

	}

	/**
	 * Create a new cash game
	 */
	private fun createNewSession(isTournament: Boolean) {

//		val sessionCount = this.feedSessionAdapter.realmResults.size
//		if (!AppGuard.isProUser && sessionCount >= AppGuard.MAX_SESSIONS_BEFORE_REQUESTING_SUBSCRIPTION) { //  && !BuildConfig.DEBUG
//			Toast.makeText(context, "Please subscribe!", Toast.LENGTH_LONG).show()
//			BillingActivity.newInstanceForResult(requireContext())
//			return
//		}

		if (Date().after(betaLimitDate)) {
			this.showEndOfBetaMessage()
			return
		}

		SessionActivity.newInstanceforResult(this, isTournament, requestCode = RequestCode.NEW_SESSION.value)
		newSessionCreated = true
	}

	/**
	 * Create a new transaction
	 */
	private fun createNewTransaction() {

		if (Date().after(betaLimitDate)) {
			this.showEndOfBetaMessage()
			return
		}
		EditableDataActivity.newInstanceForResult(this, LiveData.TRANSACTION, null, RequestCode.NEW_TRANSACTION.value)

//		EditableDataActivity.newInstance(requireContext(), LiveData.TRANSACTION.ordinal)
	}

	/**
	 * Delete selected transaction
	 */
	private fun deleteSelectedTransaction() {
		val realm = getRealm()
		realm.beginTransaction()
		selectedTransaction?.deleteFromRealm()
		realm.commitTransaction()
		selectedTransactionPosition = -1
	}

	/**
	 * Show end of beta message
	 */
	private fun showEndOfBetaMessage() {
		Toast.makeText(
			context,
			"Beta has ended. Thanks a lot for your participation! Please update with the Google Play version to continue using the app",
			Toast.LENGTH_LONG
		).show()
	}


	// Filter Handler

	override fun applyFilter() {
		super.applyFilter()

		val filter: Filter? = this.currentFilter(this.requireContext(), getRealm())
		this.loadSessions(filter)
		this.loadTransactions(filter)

		filter?.let {
            when (it.filterableType) {
                FilterableType.SESSION -> {
                    recyclerView.adapter = feedSessionAdapter
	                this.selectTab(Tab.SESSIONS)
                }
                FilterableType.TRANSACTION -> {
                    recyclerView.adapter = feedTransactionAdapter
	                this.selectTab(Tab.TRANSACTIONS)
                }
                else -> {
                }
            }
			adapterHasBeenSet = true
		}

		if (!adapterHasBeenSet) {
			adapterHasBeenSet = true
			recyclerView.adapter = feedSessionAdapter
		}
	}

	override fun removeFilter() {
		super.removeFilter()

		this.loadSessions()
		this.loadTransactions()
		if (currentFilterable == FilterableType.SESSION) {
			recyclerView.adapter = feedSessionAdapter
		} else {
			recyclerView.adapter = feedTransactionAdapter
		}
	}

	private fun selectTab(tab: Tab) {
		this.tabs.getTabAt(tab.ordinal)?.select()
	}

}