package com.jaytux.simd.frontend.client

import androidx.compose.runtime.mutableStateOf
import com.jaytux.simd.frontend.OrError
import com.jaytux.simd.frontend.immutable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

object Loader {
    val progressInit = "Initializing..."
    val progressFailed = "Finished (failed)"
    val progressFinished = "Finished"

    fun <T> CoroutineScope.loadAll(
        client: suspend () -> OrError<Client.PaginatedResponse<T>>,
        onError: suspend (String) -> Unit,
        onFinishSuccess: suspend (List<T>) -> Unit,
        onStatusChange: suspend (String) -> Unit,
        onProgress: suspend (List<T>) -> Unit = {},
        throttleBefore: Long = 0,
    ) = launch {
        delay(throttleBefore) // in case of UI-driven loading

        onStatusChange(progressInit)

        client().foldSuspend({
            onStatusChange(progressFailed)
            onError(it)
        }) { pg ->
            onStatusChange("Loading ${pg.currentPage() + 1}/${pg.totalPages()}")
            val res = pg.currentItems().toMutableList()
            var anyError = false

            while (pg.hasNextPage() && !anyError) {
                pg.loadNextPage().foldSuspend({
                    onStatusChange(progressFailed)
                    onError(it)
                    anyError = true
                }) {
                    onStatusChange("Loading ${pg.currentPage() + 1}/${pg.totalPages()}")
                    res.addAll(pg.currentItems())
                    onProgress(res)
                }
            }

            if (!anyError) {
                onStatusChange(progressFinished)
                onFinishSuccess(res)
            }
        }
    }
}