package net.pokeranalytics.android.model

import android.content.Context
import io.realm.Realm
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.Sort
import io.realm.kotlin.where
import net.pokeranalytics.android.R
import net.pokeranalytics.android.model.interfaces.CountableUsage
import net.pokeranalytics.android.model.interfaces.Manageable
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.view.Localizable

/**
 * An enum managing the business objects related to a realm results
 */
enum class LiveData : Localizable {
	BANKROLL,
	GAME,
	LOCATION,
	TOURNAMENT_NAME,
	TOURNAMENT_FEATURE,
	TRANSACTION,
	TRANSACTION_TYPE;

	fun items(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): RealmResults<*> {
		var results = realm.where(this.relatedEntity).findAll().sort(fieldName ?: this.sortingFieldName, sortOrder ?: this.sorting)

		if (results.size > 0) {
			if (results.first() is CountableUsage) {
				this.setUseCount(realm, results)
				return results.sort("useCount", Sort.DESCENDING)
			}
		}
		return results
	}

	fun setUseCount(realm: Realm, realmResults: RealmResults<*>) {
		realm.executeTransaction {
			realmResults.forEach { countableUsage ->

				when (this) {
					TOURNAMENT_FEATURE -> {
						(countableUsage as CountableUsage).useCount = it.where<Session>().contains(
							"tournamentFeatures.id",
							countableUsage.id
						).count().toInt()
					}
					else -> {
						(countableUsage as CountableUsage).useCount = it.where<Session>().equalTo(
							"${relatedEntity.simpleName.decapitalize()}.id",
							countableUsage.id
						).count().toInt()
					}
				}

			}
		}
	}

	/**
	 * Return a copy of a RealmResults
	 */
	fun itemsArray(realm: Realm, fieldName: String? = null, sortOrder: Sort? = null): ArrayList<*> {
		val results: ArrayList<Any> = ArrayList()
		results.addAll(
			realm.copyFromRealm(
				realm.where(this.relatedEntity).findAll().sort(
					fieldName ?: this.sortingFieldName, sortOrder ?: this.sorting
				)
			)
		)

		return results
	}

	private val sortingFieldName: String
		get() {
			return when (this) {
				TRANSACTION -> "date"
				else -> "name"
			}
		}

	private val sorting: Sort
		get() {
			return when (this) {
				TRANSACTION -> Sort.DESCENDING
				else -> Sort.ASCENDING
			}
		}

	private val relatedEntity: Class<out RealmObject>
		get() {
			return when (this) {
				BANKROLL -> Bankroll::class.java
				GAME -> Game::class.java
				LOCATION -> Location::class.java
				TOURNAMENT_NAME -> TournamentName::class.java
				TOURNAMENT_FEATURE -> TournamentFeature::class.java
				TRANSACTION -> Transaction::class.java
				TRANSACTION_TYPE -> TransactionType::class.java
			}
		}

	fun deleteData(realm: Realm, data: Manageable) {
		realm.where(this.relatedEntity).equalTo("id", data.id).findAll().deleteAllFromRealm()
	}

	fun updateOrCreate(realm: Realm, primaryKey: String?): RealmObject {
		val proxyItem: RealmObject? = this.getData(realm, primaryKey)
		proxyItem?.let {
			return realm.copyFromRealm(it)
		} ?: run {
			return this.newEntity()
		}
	}

	fun newEntity(): RealmObject {
		return this.relatedEntity.newInstance()
	}

	fun getData(realm: Realm, primaryKey: String?): RealmObject? {
		var proxyItem: RealmObject? = null
		primaryKey?.let {
			val t = realm.where(this.relatedEntity).equalTo("id", it).findFirst()
			t?.let {
				proxyItem = t
			}
		}
		return proxyItem
	}

	override val resId: Int?
		get() {
			return when (this) {
				BANKROLL -> R.string.bankroll
				GAME -> R.string.game
				LOCATION -> R.string.location
				TOURNAMENT_NAME -> R.string.tournament_name
				TOURNAMENT_FEATURE -> R.string.tournament_feature
				TRANSACTION -> R.string.operations
				TRANSACTION_TYPE -> R.string.operation_types
			}
		}

	/**
	 * Return the new entity title
	 */
	fun newEntityLocalizedTitle(context: Context): String {
		return "${context.getString(R.string.new_entity)} ${this.localizedTitle(context)}"
	}

}
