namespace InnovEnergy.Lib.Utils.Try;

public partial class TrySync<R>
{
    public TrySync<R> OnError<E>(Func<E, R> onError) where E : Exception
    {
        R TryIt()
        {
            try
            {
                return Func();
            }
            catch (E e)
            {
                return onError(e);
            }
        }

        return new TrySync<R>(TryIt);
    }

    public TrySync<R> OnError<E>(Func<E, Func<R>, R> onError) where E : Exception
    {
        R TryIt()
        {
            try
            {
                return Func();
            }
            catch (E e)
            {
                return onError(e, Func);
            }
        }

        return new TrySync<R>(TryIt);
    }

    public TrySync<S> ThenTry<S>(Func<R, S> map)
    {
        S MapIt()
        {
            var r = Throw();
            return map(r);
        }

        return new TrySync<S>(MapIt);
    }


    public TrySync<R> Retry<E>(Func<E, Boolean> shouldRetry) where E:Exception
    {
        R TryIt()
        {
            while(true)
            {
                try
                {
                    return Func();
                }
                catch (E e)
                {
                    if (!shouldRetry(e))
                        throw;
                }
            }
        }

        return new TrySync<R>(TryIt);
    }


    public TrySync<R> OnErrorDo<E>(Action<E> onError) where E:Exception
    {
        R TryIt()
        {
            try
            {
                return Func();
            }
            catch (E e)
            {
                onError(e);
                throw;
            }
        }

        return new TrySync<R>(TryIt);
    }

    public TrySync<R> OnSuccessDo(Action<R> onSuccess)
    {
        R DoIt()
        {
            var result = Func();
            onSuccess(result);
            return result;
        }

        return new TrySync<R>(DoIt);
    }




    public TrySync<S> Block<S>(Func<TrySync<R>, TrySync<S>> map)
    {
        return map(this);
    }

}