package net.pokeranalytics.android.util.extensions

import io.realm.*
import io.realm.kotlin.where
import net.pokeranalytics.android.model.interfaces.CountableUsage
import net.pokeranalytics.android.model.interfaces.Identifiable
import net.pokeranalytics.android.model.interfaces.NameManageable
import net.pokeranalytics.android.model.realm.*
import net.pokeranalytics.android.ui.interfaces.FilterableType

fun <T : Identifiable> Realm.findById(clazz: Class<T>, id: String) : T? {
	return this.where(clazz).equalTo("id", id).findFirst()
}

inline fun <reified T: Identifiable> Realm.findById(id: String) : T? {
	return this.findById(T::class.java, id)
}

fun <T: NameManageable> Realm.getOrCreate(clazz: Class<T>, name: String) : T {
	val instance = this.where(clazz).equalTo("name", name).findFirst()
	return if (instance != null) {
		instance
	} else {
		val newInstance = clazz.newInstance()
		newInstance.name = name
		this.copyToRealm(newInstance)
	}
}

inline fun <reified T: NameManageable> Realm.getOrCreate(name: String) : T {
	return this.getOrCreate(T::class.java, name)
}

/**
 * Returns all entities of the [clazz] sorted with their default sorting
 * Set [editableOnly] to true to only receive entities that can be edited
 */
fun < T : RealmModel> Realm.sorted(clazz: Class<T>, editableOnly: Boolean = false, filterableTypeUniqueIdentifier: Int? = null) : RealmResults<T> {
    val query = this.where(clazz)
    when (clazz.kotlin) {
        TransactionType::class -> {
            if (editableOnly) {
                query.equalTo("lock", false)
            }
        }
        Filter::class -> {
            filterableTypeUniqueIdentifier?.let {
                query.equalTo("filterableTypeUniqueIdentifier", it)
            }
        }
    }

    val items = query.findAll()
    var sortField = arrayOf("name")
    var resultSort = arrayOf(Sort.ASCENDING)

    when (items.firstOrNull()) {
        is Transaction -> {
            sortField = arrayOf("date")
            resultSort = arrayOf(Sort.DESCENDING)
        }
        is Filter -> {
            sortField = arrayOf("useCount", "name")
            resultSort = arrayOf(Sort.DESCENDING, Sort.ASCENDING)
        }
        is CountableUsage -> {
            this.updateUsageCount(clazz)
            sortField = arrayOf("useCount")
            resultSort = arrayOf(Sort.DESCENDING)
        }
    }
    return items.sort(sortField, resultSort)
}

/**
 * Returns all entities of the [C] class sorted with their default sorting
 */
inline fun <reified C : RealmModel> Realm.sorted(editableOnly: Boolean = false) : RealmResults<C> {
	return this.sorted(C::class.java, editableOnly)
}

/**
 * Updates the useCount variable of the CountableUsage entity
 */
fun <T : RealmModel>Realm.updateUsageCount(clazz: Class<T>) {

	val results = this.where(clazz).findAll()
	this.executeTransaction {
		results.forEach { countableUsage ->

			val countable = (countableUsage as CountableUsage)
			val fieldName = when (clazz.kotlin) {
				TournamentFeature::class -> "tournamentFeatures.id"
				else -> "${clazz.simpleName.decapitalize()}.id"
			}
			val count = it.where<Session>().contains(fieldName, countable.id).count().toInt()
			countable.useCount = count
		}
	}

}