package dev.jriley.hackernews.data

import dev.jriley.hackernews.services.HackerNewsService
import dev.jriley.hackernews.services.KotlinServices
import io.reactivex.Flowable
import io.reactivex.Scheduler
import io.reactivex.Single
import io.reactivex.schedulers.Schedulers
import timber.log.Timber

class StoryRepository(private val storyData: StoryData = DatabaseProvider.dataBase.storyEntityDao(),
                      private val hackerNewsService: HackerNewsService = KotlinServices.hackerNewsService,
                      private val ioScheduler: Scheduler = Schedulers.io()) {

    fun isLoaded(): Single<Boolean> = storyData.isLoaded().subscribeOn(ioScheduler)

    fun loadBest(): Single<List<Long>> = loadStoryIds(hackerNewsService.best, StoryTypes.BEST)

    fun loadTop(): Single<List<Long>> = loadStoryIds(hackerNewsService.top, StoryTypes.TOP)

    fun loadNew(): Single<List<Long>> = loadStoryIds(hackerNewsService.new, StoryTypes.NEW)

    fun flowBest(): Flowable<List<Story>> = storyData.storyList()

    fun bookmarkStory(story: Story): Single<Int> = storyData.update(story).subscribeOn(ioScheduler)

    private fun loadStoryIds(api: Single<List<Long>>, st: StoryTypes): Single<List<Long>> =
            api.map { id -> Timber.tag("@@@@").i("Original $st size: ${id.size}"); id.filter { !storyData.isLoaded(it) } }
                    .toObservable()
                    .flatMapIterable { filteredList -> Timber.tag("@").i("Filtered size:${filteredList.size}"); filteredList }
                    .map { filteredId -> hackerNewsService.getStory(filteredId.toString()) }
                    .map { story -> storyData.insert(Story(story.blockingGet(), st)) }
                    .map { storyId -> storyId.blockingGet() }
                    .toList()
                    .subscribeOn(ioScheduler)

}

object StoryRepositoryFactory {
    val storyRepository: StoryRepository by lazy { StoryRepository() }
}
