package net.pokeranalytics.android.model.realm

import io.realm.RealmList
import io.realm.RealmObject
import io.realm.RealmResults
import io.realm.annotations.Ignore
import io.realm.annotations.LinkingObjects
import io.realm.annotations.RealmClass
import net.pokeranalytics.android.model.filter.Filterable
import net.pokeranalytics.android.model.filter.QueryCondition

@RealmClass
open class Result : RealmObject(), Filterable {

	companion object {

		fun fieldNameForQueryType(queryCondition: Class < out QueryCondition>): String? {
			Session.fieldNameForQueryType(queryCondition)?.let {
				return "sessions.$it"
			}
			return null
		}

	}
	/**
	 * The buyin amount
 	 */
    var buyin: Double? = null
        set(value) {
            field = value
            this.computeNumberOfRebuy()
            this.computeNet()
        }

	/**
	 * The cashed out amount
 	 */
    var cashout: Double? = null
        set(value) {
            field = value
            this.computeNet()
	        if (value != null) {
		        this.session?.end()
	        }
        }

	/**
	 * The net result
	 */
	var netResult: Double? = null
		set(value) {

			this.session?.bankroll?.let { bankroll ->
				if (bankroll.live) {
					throw IllegalStateException("Can't set net result on a live bankroll")
				}
			} ?: run {
				throw IllegalStateException("Session doesn't have any bankroll")
			}

			field = value
			this.computeNet()
			if (value != null) {
				this.session.end()
			}
		}

	/**
	 * The pre-computed net (readonly)
	 */
	var net: Double = 0.0
		private set

	/**
	 * Tips
 	 */
	var tips: Double? = null

	// The transactions associated with the Result, impacting the result
    var transactions: RealmList<Transaction> = RealmList()
        set(value) {
            field = value
            this.computeNet()
        }

    // The tournament final position, if applicable
    var tournamentFinalPosition: Int? = null

    // Number of rebuys
    var numberOfRebuy: Double? = null

	@LinkingObjects("result")
	private val sessions: RealmResults<Session>? = null

	@Ignore
	val session: Session? = this.sessions?.firstOrNull()

	/**
	 * Returns 1 if the session is positive
	 */
	@Ignore
	val isPositive: Int = if (this.net >= 0.0) 1 else 0

    // Computes the Net
    private fun computeNet() {

        val transactionsSum = transactions.sumByDouble { it.amount }

	    val isLive = this.session?.isLive ?: true
	    if (isLive) {
		    val buyin = this.buyin ?: 0.0
		    val cashOut = this.cashout ?: 0.0
		    this.net = cashOut - buyin + transactionsSum
	    } else {
		    val netResult = this.netResult ?: 0.0
		    this.net = netResult + transactionsSum
	    }

	    // Precompute results
		this.session?.computeStats()
	    this.session?.sessionSet?.computeStats()
    }

    // Computes the number of rebuy
    fun computeNumberOfRebuy() {
        this.session?.let {
            if (it.isCashGame()) {
                it.cgBigBlind?.let { bb ->
                    if (bb > 0.0) {
                        this.numberOfRebuy = (this.buyin ?: 0.0) / (bb * 100.0)
                    } else {
                        this.numberOfRebuy = null
                    }
                }
            } else {
                it.tournamentEntryFee?.let { entryFee ->
                    if (entryFee > 0.0) {
                        this.numberOfRebuy = (this.buyin ?: 0.0) / entryFee
                    } else {
                        this.numberOfRebuy = null
                    }
                }
            }
        }
    }

	// @todo tips?

}