// Copyright (c) 2025 GeWuYou
// 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.

using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;

namespace GFramework.Core.Functional;

/// <summary>
///     表示一个无值的操作结果，仅包含成功或失败状态
/// </summary>
[StructLayout(LayoutKind.Auto)]
public readonly struct Result : IEquatable<Result>
{
    private readonly Exception? _exception;
    private readonly bool _isSuccess;

    /// <summary>
    ///     私有构造函数，用于创建 Result 实例
    /// </summary>
    /// <param name="isSuccess">是否为成功状态</param>
    /// <param name="exception">失败时的异常信息</param>
    private Result(bool isSuccess, Exception? exception)
    {
        // 强制不变式：失败状态必须携带非空异常
        if (!isSuccess && exception is null)
            throw new ArgumentException("Failure Result must have a non-null exception.", nameof(exception));

        _isSuccess = isSuccess;
        _exception = exception;
    }

    /// <summary>
    ///     判断结果是否为成功状态
    /// </summary>
    [Pure]
    public bool IsSuccess => _isSuccess;

    /// <summary>
    ///     判断结果是否为失败状态
    /// </summary>
    [Pure]
    public bool IsFailure => !_isSuccess;

    /// <summary>
    ///     获取失败时的异常信息，若为成功状态则抛出 InvalidOperationException
    /// </summary>
    [Pure]
    public Exception Error => IsFailure
        ? _exception!
        : throw new InvalidOperationException("Cannot access Error on a successful Result.");

    /// <summary>
    ///     创建成功结果
    /// </summary>
    /// <returns>成功结果</returns>
    [Pure]
    public static Result Success() => new(true, null);

    /// <summary>
    ///     创建失败结果
    /// </summary>
    /// <param name="ex">失败的异常</param>
    /// <returns>失败结果</returns>
    [Pure]
    public static Result Failure(Exception ex)
    {
        ArgumentNullException.ThrowIfNull(ex);
        return new(false, ex);
    }

    /// <summary>
    ///     根据错误消息创建失败结果
    /// </summary>
    /// <param name="message">错误消息</param>
    /// <returns>失败结果</returns>
    [Pure]
    public static Result Failure(string message)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(message);
        return new Result(false, new InvalidOperationException(message));
    }

    /// <summary>
    ///     根据成功或失败状态分别执行不同的处理逻辑
    /// </summary>
    /// <typeparam name="R">返回值类型</typeparam>
    /// <param name="onSuccess">成功时执行的函数</param>
    /// <param name="onFailure">失败时执行的函数</param>
    /// <returns>处理后的结果</returns>
    public R Match<R>(Func<R> onSuccess, Func<Exception, R> onFailure) =>
        IsSuccess ? onSuccess() : onFailure(_exception!);

    /// <summary>
    ///     将当前无值的 Result 提升为带值的 Result
    /// </summary>
    /// <typeparam name="A">值的类型</typeparam>
    /// <param name="value">成功时关联的值</param>
    /// <returns>带值的 Result</returns>
    [Pure]
    public Result<A> ToResult<A>(A value) =>
        IsSuccess ? Result<A>.Success(value) : Result<A>.Failure(_exception!);

    /// <summary>
    ///     判断当前 Result 是否与另一个 Result 相等
    /// </summary>
    /// <param name="other">另一个 Result</param>
    /// <returns>若相等返回 true，否则返回 false</returns>
    [Pure]
    public bool Equals(Result other)
    {
        if (_isSuccess != other._isSuccess)
            return false;

        if (_isSuccess)
            return true;

        if (_exception is null || other._exception is null)
            return _exception is null && other._exception is null;

        return _exception.GetType() == other._exception.GetType() &&
               string.Equals(_exception.Message, other._exception.Message, StringComparison.Ordinal);
    }

    /// <summary>
    ///     判断当前对象是否与另一个对象相等
    /// </summary>
    /// <param name="obj">另一个对象</param>
    /// <returns>若相等返回 true，否则返回 false</returns>
    [Pure]
    public override bool Equals(object? obj) => obj is Result other && Equals(other);

    /// <summary>
    ///     获取当前 Result 的哈希码
    /// </summary>
    /// <returns>哈希码</returns>
    [Pure]
    public override int GetHashCode()
    {
        if (_isSuccess)
            return 1;

        return _exception is null
            ? 0
            : HashCode.Combine(_exception.GetType(), _exception.Message);
    }

    /// <summary>
    ///     判断两个 Result 是否相等
    /// </summary>
    /// <param name="a">第一个 Result</param>
    /// <param name="b">第二个 Result</param>
    /// <returns>若相等返回 true，否则返回 false</returns>
    [Pure]
    public static bool operator ==(Result a, Result b) => a.Equals(b);

    /// <summary>
    ///     判断两个 Result 是否不相等
    /// </summary>
    /// <param name="a">第一个 Result</param>
    /// <param name="b">第二个 Result</param>
    /// <returns>若不相等返回 true，否则返回 false</returns>
    [Pure]
    public static bool operator !=(Result a, Result b) => !a.Equals(b);

    /// <summary>
    ///     返回当前 Result 的字符串表示
    /// </summary>
    /// <returns>Result 的字符串表示</returns>
    [Pure]
    public override string ToString() =>
        _isSuccess ? "Success" : (_exception != null ? $"Fail({_exception.Message})" : "Fail(null)");

    /// <summary>
    ///     尝试执行一个无返回值的操作，并根据执行结果返回成功或失败的 Result
    /// </summary>
    /// <param name="action">要执行的无返回值操作</param>
    /// <returns>若操作成功执行返回成功的 Result，若执行过程中抛出异常则返回失败的 Result</returns>
    [Pure]
    public static Result Try(Action action)
    {
        ArgumentNullException.ThrowIfNull(action);
        try
        {
            action();
            return Success();
        }
        catch (Exception ex)
        {
            return Failure(ex);
        }
    }

    /// <summary>
    ///     将当前 Result 的成功结果映射为另一种类型的 Result
    /// </summary>
    /// <typeparam name="B">映射后的目标类型</typeparam>
    /// <param name="func">用于转换值的函数</param>
    /// <returns>若当前为成功状态，返回包含转换后值的成功 Result；若为失败状态，返回保持原有错误的失败 Result</returns>
    public Result<B> Map<B>(Func<B> func)
    {
        ArgumentNullException.ThrowIfNull(func);
        return IsSuccess ? Result<B>.Success(func()) : Result<B>.Failure(_exception!);
    }

    /// <summary>
    ///     将当前 Result 绑定到一个返回 Result 的函数上
    /// </summary>
    /// <typeparam name="B">Result 中值的类型</typeparam>
    /// <param name="func">返回 Result 的函数</param>
    /// <returns>若当前为成功状态，返回函数执行的结果；若为失败状态，返回保持原有错误的失败 Result</returns>
    public Result<B> Bind<B>(Func<Result<B>> func)
    {
        ArgumentNullException.ThrowIfNull(func);
        return IsSuccess ? func() : Result<B>.Failure(_exception!);
    }
}
