/*
 * Copyright KG Soft
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
@file:JvmName("CoroutinesExtensions")

package com.kgurgul.cpuinfo.utils

import com.kgurgul.cpuinfo.utils.wrappers.Result
import kotlin.jvm.JvmName
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

/**
 * Wrap passed [block] with [Result]. Flow will always start with [Result.Loading] and finish with
 * [Result.Success] in case of success otherwise it will emit [Result.Error].
 */
fun <T> wrapToResultFlow(block: suspend () -> T): Flow<Result<T>> = flow {
    emit(Result.Loading)
    try {
        val result = block()
        emit(Result.Success(result))
    } catch (ce: CancellationException) {
        throw ce
    } catch (throwable: Throwable) {
        CpuLogger.e(throwable) { "Error during wrapping to Result" }
        emit(Result.Error(throwable))
    }
}

/**
 * Create flow from suspended function wrapped with [Result]. Flow will always start with
 * [Result.Loading] and finish with [Result.Success] in case of success otherwise it will emit
 * [Result.Error].
 */
fun <T> (suspend () -> T).asResultFlow(): Flow<Result<T>> = flow {
    emit(Result.Loading)
    try {
        val result = invoke()
        emit(Result.Success(result))
    } catch (ce: CancellationException) {
        throw ce
    } catch (throwable: Throwable) {
        CpuLogger.e(throwable) { "Error during wrapping to Result" }
        emit(Result.Error(throwable))
    }
}

expect val ioDispatcher: CoroutineDispatcher
