package com.dropbox.android.sample.ui.stream

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
import androidx.fragment.app.Fragment
import com.dropbox.android.external.store4.Fetcher
import com.dropbox.android.external.store4.MemoryPolicy
import com.dropbox.android.external.store4.StoreBuilder
import com.dropbox.android.external.store4.StoreRequest
import com.dropbox.android.external.store4.fresh
import com.dropbox.android.external.store4.get
import com.dropbox.android.sample.R
import kotlin.coroutines.CoroutineContext
import kotlin.time.ExperimentalTime
import kotlin.time.seconds
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flattenMerge
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.launch

@ExperimentalTime
class StreamFragment : Fragment(), CoroutineScope {

    private val get_1: Button get() = requireView().findViewById(R.id.get_1)

    private val get_2: Button get() = requireView().findViewById(R.id.get_2)

    private val fresh_1: Button get() = requireView().findViewById(R.id.fresh_1)

    private val fresh_2: Button get() = requireView().findViewById(R.id.fresh_2)

    private val stream_1: TextView get() = requireView().findViewById(R.id.stream_1)

    private val stream_2: TextView get() = requireView().findViewById(R.id.stream_2)

    private val stream: TextView get() = requireView().findViewById(R.id.stream)

    override val coroutineContext: CoroutineContext = Job() + Dispatchers.Main

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_stream, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        var counter = 0

        val store = StoreBuilder
            .from(
                Fetcher.of { key: Int ->
                    (key * 1000 + counter++).also { delay(1_000) }
                }
            )
            .cachePolicy(
                MemoryPolicy
                    .builder<Any, Any>()
                    .setExpireAfterWrite(10.seconds)
                    .build()
            )
            .build()

        get_1.onClick {
            store.get(1)
        }

        fresh_1.onClick {
            store.fresh(1)
        }

        get_2.onClick {
            store.get(2)
        }

        fresh_2.onClick {
            store.fresh(2)
        }

        launch {
            store.stream(StoreRequest.cached(1, refresh = false)).collect {
                stream_1.text = "Stream 1 $it"
            }
        }
        launch {
            store.stream(StoreRequest.cached(2, refresh = false)).collect {
                stream_2.text = "Stream 2 $it"
            }
        }
        launch {
            flowOf(
                store.stream(StoreRequest.cached(1, refresh = false)),
                store.stream(StoreRequest.cached(2, refresh = false))
            )
                .flattenMerge()
                .collect {
                    stream.text = "Stream $it"
                }
        }
    }

    fun View.onClick(f: suspend () -> Unit) {
        setOnClickListener {
            launch {
                f()
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        coroutineContext.cancel()
    }
}
