package app.furmeet.events.system.schedule

import android.content.res.ColorStateList
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import app.furmeet.events.bff.R
import app.furmeet.events.system.TranslatableAppCompatActivityWithScheduleServiceWrapped
import app.furmeet.events.system.helper.*
import app.furmeet.events.system.helper.observables.Observer
import app.furmeet.events.system.schedule.abstractDataTypes.convention.FilterableNamedColoredAttribute
import app.furmeet.events.system.schedule.abstractDataTypes.convention.Place
import app.furmeet.events.system.schedule.abstractDataTypes.convention.Tag
import app.furmeet.events.system.schedule.abstractDataTypes.dataholder.PeekableEvent
import app.furmeet.events.system.schedule.adapters.FilterCriteriaRecyclerViewAdapter
import app.furmeet.events.system.schedule.adapters.PeekableEventRecyclerViewAdapter
import app.furmeet.events.system.schedule.adapters.TagTripleListAdapter
import app.furmeet.events.bff.databinding.ActivitySearchFilterBinding

//import kotlinx.android.synthetic.main.activity_search_filter.*
//import org.jetbrains.anko.doAsync
//import org.jetbrains.anko.uiThread

class SearchFilterActivity : TranslatableAppCompatActivityWithScheduleServiceWrapped() {
    lateinit var binding: ActivitySearchFilterBinding
    val tags = mutableListOf<Tag>()
    val places = mutableListOf<Place>()
    var query = ""
    lateinit var filteredEventsListAdapter: PeekableEventRecyclerViewAdapter
    lateinit var filterTagsListAdapter: FilterCriteriaRecyclerViewAdapter<Tag>
    lateinit var filterPlacesListAdapter: FilterCriteriaRecyclerViewAdapter<Place>
    lateinit var everyPeekableEvent: List<PeekableEvent>
    val observer = Observer { _, _: Any? ->
        runOnUiThread {
            updateView()
        }
    }

    private val nullPair = Pair(null, nullFun)

    override fun onCreate(savedInstanceState: Bundle?) {
        ActivitiesForFragments[this.javaClass.simpleName] = this
        super.onCreate(savedInstanceState)
        binding = ActivitySearchFilterBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        scheduleManager.convention.colorScheme?.primaryDarker?.let {
            binding.queryText.backgroundTintList = ColorStateList.valueOf(it)
        }
        scheduleManager.convention.colorScheme?.primaryLighter?.let {
            binding.queryText.setHintTextColor(it)
        }
        scheduleManager.convention.colorScheme?.primaryRegular?.let {
            window!!.statusBarColor = it
            binding.queryTextContainer.backgroundTintList = ColorStateList.valueOf(it)
            binding.filters.backgroundTintList = ColorStateList.valueOf(it)
            binding.filterCriteriaTags.backgroundTintList = ColorStateList.valueOf(it)
            binding.filterCriteriaPlaces.backgroundTintList = ColorStateList.valueOf(it)
        }
        binding.placeFiltersContainer.visibility = if (scheduleManager.convention.places.size < 2) View.GONE else View.VISIBLE
        binding.categoryFiltersContainer.visibility = if (scheduleManager.convention.tags.size < 2) View.GONE else View.VISIBLE
        resourcesAliased = this.resources
        scheduleManager.addObserver(observer)
        binding.queryText.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable?) {
                query = s.toString()
                updateView()
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
        })
        val rl = binding.recyclerList!!
        val fct = binding.filterCriteriaTags!!
        val fcp = binding.filterCriteriaPlaces!!
        val pr = scheduleManager.convention.colorScheme?.primaryRegular
        val ac = scheduleManager.convention.colorScheme?.accentColor
        filteredEventsListAdapter = PeekableEventRecyclerViewAdapter(mutableListOf(), scheduleManager, this, ac) { updateView() }
        filterTagsListAdapter = FilterCriteriaRecyclerViewAdapter(listOf(), pr) { callAddTags() }
        filterPlacesListAdapter = FilterCriteriaRecyclerViewAdapter(listOf(), pr) { callAddPlaces() }
        rl.adapter = filteredEventsListAdapter
        rl.layoutManager = LinearLayoutManager(this@SearchFilterActivity)
        everyPeekableEvent = (
                scheduleManager.convention.events.map { PeekableEvent(it) } +
                        scheduleManager.attendeeFavorites.toList().filter { it.isCustom }.map { PeekableEvent(it) }
                ).sortedWith(compareBy(
                { it.timeRange.start.timeInMillis },
                { it.timeRange.finish.timeInMillis },
                { it.title.solved }
        ))
        fct.adapter = filterTagsListAdapter
        fct.layoutManager = LinearLayoutManager(this@SearchFilterActivity, LinearLayoutManager.HORIZONTAL, false)
        fcp.adapter = filterPlacesListAdapter
        fcp.layoutManager = LinearLayoutManager(this@SearchFilterActivity, LinearLayoutManager.HORIZONTAL, false)
        updateView()
        onBackPressDispatcherAddCallbackCompat { handleBackPressed() }
    }

    private fun handleBackPressed() {
        scheduleManager.deleteObserver(observer)
        finish()
    }

    private fun <T : FilterableNamedColoredAttribute> callAddSomething(
            wholeCollection: Collection<T>,
            currentCollection: MutableCollection<T>,
            @StringRes dialogTitleResource: Int
    ) {
        doAsync {
            val placeChoices = wholeCollection.filterNot {
                it in currentCollection
            }.map {
                Triple(it.names.solved!!, it.color, { currentCollection.add(it) })
            }
            uiThread {
                val choicesAdapted = TagTripleListAdapter(placeChoices)
                AlertDialog.Builder(this@SearchFilterActivity)
                        .setTitle(dialogTitleResource)
                        .setAdapter(choicesAdapted) { dialog, which: Int ->
                            placeChoices[which].third()
                            dialog.dismiss()
                            updateView()
                        }
                        .show()
            }
        }
    }

    fun callAddPlaces() = callAddSomething(
            scheduleManager.convention.places,
            places,
            R.string.schedule_event_key_places
    )

    fun callAddTags() = callAddSomething(
            scheduleManager.convention.tags,
            tags,
            R.string.schedule_event_key_categories
    )

    fun <T : FilterableNamedColoredAttribute> updateFilterItemView(
            wholeCollection: Collection<T>,
            currentCollection: MutableCollection<T>,
            adapter: FilterCriteriaRecyclerViewAdapter<T>
    ) {
        doAsync {
            val hasPlusButtons = currentCollection.size < wholeCollection.size
            val plusButtons = if (hasPlusButtons) listOf(nullPair) else listOf()
            val filterableChoices = currentCollection.map {
                Pair(it) { currentCollection.remove(it); updateView() }
            }.let {
                when (it.size) {
                    0 -> plusButtons
                    1 -> plusButtons + it
                    else -> plusButtons + it + plusButtons
                }
            }
            uiThread {
                adapter.onDataChanged(filterableChoices)
            }
        }
    }

    fun updateView() {
        updateFilterItemView(
                scheduleManager.convention.tags,
                tags,
                filterTagsListAdapter
        )
        updateFilterItemView(
                scheduleManager.convention.places,
                places,
                filterPlacesListAdapter
        )
        doAsync {
            val toRemoveByName = if (query.isEmpty()) listOf() else
                everyPeekableEvent.filter {
                    (query.lowercase() !in it.title.solved?.lowercase() ?: "")
                            &&
                            (query.lowercase() !in it.subtitles?.solved?.lowercase() ?: "")
                            &&
                            (query.lowercase() !in it.descriptions?.solved?.lowercase() ?: "")
                }
            val toRemoveByTag = if (tags.isEmpty()) listOf() else
                everyPeekableEvent.filter { event ->
                    !tags.any { event.tags?.contains(it) ?: false }
                }
            val toRemoveByPlace = if (places.isEmpty()) listOf() else
                everyPeekableEvent.filter { event ->
                    !places.any { event.places?.contains(it) ?: false }
                }
            val toDisplay = everyPeekableEvent - (toRemoveByName + toRemoveByTag + toRemoveByPlace).toSet()
            filteredEventsListAdapter.onDataChanged(toDisplay)
        }
    }
}
