package net.pokeranalytics.android.model.realm

import io.realm.RealmList
import io.realm.RealmObject
import net.pokeranalytics.android.exceptions.PokerAnalyticsException
import net.pokeranalytics.android.model.filter.QueryCondition
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow
import net.pokeranalytics.android.ui.view.rowrepresentable.FilterElementRow.*
import java.util.*

open class FilterCondition() : RealmObject() {

    private constructor(filterName:String, sectionName:String) : this() {
        this.filterName = filterName
        this.sectionName = sectionName
    }

    constructor(filterElementRows: ArrayList<FilterElementRow>) : this(filterElementRows.first().id, filterElementRows.first().filterSectionRow.name) {
        val row = filterElementRows.first()
        this.filterName ?: throw PokerAnalyticsException.FilterElementUnknownName

        when (row) {
            is DateFilterElementRow -> {
                this.dateValue = row.dateValue
            }
            is Blind -> {
                //TODO refactor raz
                this.stringValues = RealmList<String>().apply {
                    this.addAll(filterElementRows.map {
                        (it as Blind).blind
                    })
                }
                this.booleanValues = RealmList<Boolean>().apply {
                    this.addAll(filterElementRows.map {
                        (it as Blind).hasDefaultCurrency
                    })
                }
            }
            is StringFilterElementRow -> {
                this.stringValues = RealmList<String>().apply {
                    this.addAll(filterElementRows.map {
                        (it as StringFilterElementRow).stringValue
                    })
                }
            }
            is NumericFilterElementRow -> {
                this.numericValues = RealmList<Double>().apply {
                    this.addAll(filterElementRows.map {
                        (it as NumericFilterElementRow).doubleValue
                    })
                }
            }
        }
    }

	var filterName: String? = null
	var sectionName: String? = null

    val queryCondition : QueryCondition
        get() = QueryCondition.valueOf(this.filterName ?: throw PokerAnalyticsException.FilterElementUnknownName)
            .apply {
                this.updateValueMap(this@FilterCondition)
            }

	private var numericValues: RealmList<Double>? = null
	private var dateValue: Date? = null
	private var stringValues: RealmList<String>? = null
    private var booleanValues: RealmList<Boolean>? = null

	val ids: Array<String>
		get() = stringValues?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing

	val blinds: Array<String>
        get() = stringValues?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing

    val hasDefaultCurrency: Array<Boolean>
        get() = booleanValues?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing

    val date: Date
		get() = dateValue ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	val values: Array<Int>
		get() = numericValues?.map {
			it.toInt()
		}?.toTypedArray() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	val value: Double
		get() = numericValues?.first() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	val leftValue: Double
		get() = numericValues?.first() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	val rightValue: Double
		get() = numericValues?.last() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	val dayOfWeek: Int
		get() = numericValues?.first()?.toInt() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	val month: Int
		get() = numericValues?.first()?.toInt() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	val year: Int
		get() = numericValues?.first()?.toInt() ?: throw PokerAnalyticsException.FilterElementExpectedValueMissing


	/**
	 * Return the value associated with the given [filterElementRow]
	 */
	fun getFilterConditionValue(filterElementRow: FilterElementRow): Any? {
		return when (filterElementRow) {
			is DateFilterElementRow -> date
			is PastDays -> values
			else -> throw PokerAnalyticsException.FilterElementTypeMissing(filterElementRow)
		}
	}

}
