package com.adealink.weparty.commonui.ext

import com.adealink.frame.base.IError
import com.adealink.frame.base.Rlt
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract

/**
 */


val Rlt<*>.isSuccess: Boolean get() = this is Rlt.Success

val Rlt<*>.isFailure: Boolean get() = this !is Rlt.Success

fun <T> Rlt<T>.getOrNull(): T? {
    return if (isSuccess) (this as Rlt.Success).data else null
}

fun Rlt<*>.exceptionOrNull(): IError? {
    return if (this is Rlt.Failed) this.error else null
}

public inline fun <T> Rlt<T>.onSuccess(action: (value: T) -> Unit): Rlt<T> {
    if (isSuccess) action((this as Rlt.Success).data)
    return this
}

public inline fun <T> Rlt<T>.onFailure(action: (value: Throwable?) -> Unit): Rlt<T> {
    if (isFailure) action((this as Rlt.Failed).error.exception)
    return this
}

@OptIn(ExperimentalContracts::class)
public inline fun <V, E> Rlt<V>.andThen(transform: (V) -> Rlt<E>): Rlt<E> {
    // kotlin 约定，告诉编译器 transform 最多执行一次
    contract {
        callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
    }
    if (isSuccess) {
        val value = getOrNull() ?: return Rlt.Failed(InnerException())
        return transform(value)
    } else {
        val exception = exceptionOrNull() ?: return Rlt.Failed(InnerException())
        return Rlt.Failed(exception)
    }
}

// 自定义异常，表示内部出错了
class InnerException(message: String = "inner value error") : IError(message)

