using UnityEngine;

namespace Combo
{
    public class Result<T> where T : Serializable
    {
        internal class Success : Result<T>
        {
            public T Value { get; private set; }

            public Success(T value)
            {
                Value = value;
            }
        }

        internal class Fail : Result<T>
        {
            public new Error Error { get; private set; }

            public Fail(Error error)
            {
                Error = error;
            }
        }

        internal static Success CreateSuccess(T value)
        {
            return new Success(value);
        }

        internal static Result<T> CreateSuccessFromJson(string json)
        {
            try
            {
                var opt = Serializable.FromJson<T>(json);
                return new Success(opt);
            }
            catch (SerializationException e)
            {
                Debug.LogError($"ComboSDKResult.CreateSuccessFromJson failed: \n\t<SRC> {json}\n\t<TARGET> ${typeof(T).Name}\n\t<CAUSE> ${e.Message} {e.StackTrace}");
                return null;
            }
        }

        internal static Fail CreateFail(string error, string message, string detailMessage)
        {
            return new Fail(new Error(error, message, detailMessage));
        }

        internal static Fail CreateFailFromJson(string json)
        {
            return new Fail(Error.CreateFromJson(json));
        }

        public bool IsSuccess
        {
            get
            {
                return this is Success;
            }
        }

        public T Data
        {
            get
            {
                if (this is Success success)
                {
                    return success.Value;
                }
                else if (this is Fail fail)
                {
                    throw fail.Error;
                }
                return default;
            }
        }

        public Error Error
        {
            get
            {
                if (this is Fail fail)
                {
                    return fail.Error;
                }
                return null;
            }
        }
    }
}