package app.furmeet.events.system.schedule.abstractDataTypes.managed

import app.furmeet.events.system.helper.UncomplicatedObservable
import app.furmeet.events.system.helper.observables.Observable
import app.furmeet.events.system.helper.observables.Observer
import app.furmeet.events.system.schedule.abstractDataTypes.convention.Convention
import app.furmeet.events.system.schedule.abstractDataTypes.convention.Event
import app.furmeet.events.system.schedule.abstractDataTypes.convention.RegistrationTier
import java.io.Serializable

class AttendeeConFavorites(convention: Convention) : UncomplicatedObservable<Any?>(), Observer<Any?>, Serializable {
    override fun update(observable: Observable<Any?>, args: Any?) = notifyObservers(args)
    val conventionId = convention.id
    private var intentions: MutableList<AttendeeConFavorite> = mutableListOf()
    private var internalRegistrationTier = convention.lowestRegistrationTier
    private var internalRegistrationTierSelectorShown = false
    var registrationTier: RegistrationTier
        get() = internalRegistrationTier
        set(value) = value.let { internalRegistrationTier = it; notifyObservers() }
    var registrationTierSelectorShown: Boolean
        get() = internalRegistrationTierSelectorShown
        set(value) = value.let { internalRegistrationTierSelectorShown = it; notifyObservers() }

    operator fun contains(that: Event) = this.find(that) != null
    operator fun contains(that: AttendeeConFavorite) = this.find(that) != null

    fun toList() = intentions.toList().sortedBy { it.timeRange.start.timeInMillis }

    fun find(that: Event) =
            indexOf(that).let { if (it < 0) null else intentions[it] }

    fun find(that: AttendeeConFavorite) =
            indexOf(that).let { if (it < 0) null else intentions[it] }

    private fun indexOf(that: AttendeeConFavorite) =
            this.intentions.withIndex().firstOrNull { it.value == that }?.index ?: -1

    private fun indexOf(that: Event) =
            this.intentions.withIndex().firstOrNull { it.value.relatesTo(that) }?.index ?: -1

    fun add(that: AttendeeConFavorite) = (if (that !in this) this.intentions.add(that) else false).apply { notifyObservers() }


    fun addAll(that: AttendeeConFavorites) = addAll(that.intentions)
    fun addAll(that: List<AttendeeConFavorite>) = this.intentions.addAll(that.filter { it !in this }.apply {
        forEach { it.addObserver(this@AttendeeConFavorites) }
    }).apply { notifyObservers() }

    fun clear() = intentions.apply {
        forEach { deleteObserver(this@AttendeeConFavorites) }
    }.clear().apply { notifyObservers() }

    fun observeAllChildren() {
        intentions.forEach {
            it.addObserver(this)
        }
    }

    fun recursivelyRemoveObservers() {
        deleteObservers()
        intentions.forEach {
            it.deleteObservers()
        }
    }

    fun remove(existing: AttendeeConFavorite) =
            indexOf(existing).let {
                if (it < 0) false else {
                    intentions.removeAt(it); notifyObservers();true
                }
            }

    fun remove(existing: Event) =
            indexOf(existing).let {
                if (it < 0) false else {
                    intentions.removeAt(it); notifyObservers();true
                }
            }

    fun canAttend(event: Event) = registrationTier.canAttend(event)
}