using System.Diagnostics;
using TakeoutSaaS.Shared.Abstractions.Diagnostics;

namespace TakeoutSaaS.Shared.Abstractions.Results;

/// <summary>
/// 统一的 API 返回结果包装。
/// </summary>
/// <typeparam name="T">数据载荷类型。</typeparam>
public sealed record ApiResponse<T>
{
    /// <summary>
    /// 是否成功。
    /// </summary>
    public bool Success { get; init; }

    /// <summary>
    /// 状态/错误码（默认 200）。
    /// </summary>
    public int Code { get; init; } = 200;

    /// <summary>
    /// 提示信息。
    /// </summary>
    public string? Message { get; init; }

    /// <summary>
    /// 业务数据。
    /// </summary>
    public T? Data { get; init; }

    /// <summary>
    /// 错误详情（如字段验证错误）。
    /// </summary>
    public object? Errors { get; init; }

    /// <summary>
    /// TraceId，便于链路追踪。
    /// </summary>
    public string TraceId { get; init; } = string.Empty;

    /// <summary>
    /// 时间戳（UTC）。
    /// </summary>
    public DateTime Timestamp { get; init; } = DateTime.UtcNow;

    /// <summary>
    /// 成功返回。
    /// </summary>
    /// <param name="data">业务数据。</param>
    /// <param name="message">提示信息。</param>
    /// <returns>封装后的成功响应。</returns>
    public static ApiResponse<T> Ok(T data, string? message = "操作成功")
        => Create(true, 200, message, data);

    /// <summary>
    /// 无数据的成功返回。
    /// </summary>
    /// <param name="message">提示信息。</param>
    /// <returns>封装后的成功响应。</returns>
    public static ApiResponse<T> Ok(string? message = "操作成功")
        => Create(true, 200, message, default);

    /// <summary>
    /// 兼容旧名称：成功结果。
    /// </summary>
    /// <param name="data">业务数据。</param>
    /// <param name="message">提示信息。</param>
    /// <returns>封装后的成功响应。</returns>
    public static ApiResponse<T> SuccessResult(T data, string? message = "操作成功")
        => Ok(data, message);

    /// <summary>
    /// 错误返回。
    /// </summary>
    /// <param name="code">错误码。</param>
    /// <param name="message">错误提示。</param>
    /// <param name="errors">错误详情。</param>
    /// <returns>封装后的失败响应。</returns>
    public static ApiResponse<T> Error(int code, string message, object? errors = null)
        => Create(false, code, message, default, errors);

    /// <summary>
    /// 兼容旧名称：失败结果。
    /// </summary>
    /// <param name="code">错误码。</param>
    /// <param name="message">错误提示。</param>
    /// <returns>封装后的失败响应。</returns>
    public static ApiResponse<T> Failure(int code, string message)
        => Error(code, message);

    /// <summary>
    /// 附加错误详情。
    /// </summary>
    /// <param name="errors">错误详情。</param>
    /// <returns>包含错误详情的新响应。</returns>
    public ApiResponse<T> WithErrors(object? errors)
        => this with { Errors = errors };

    private static ApiResponse<T> Create(bool success, int code, string? message, T? data, object? errors = null)
        => new()
        {
            Success = success,
            Code = code,
            Message = message,
            Data = data,
            Errors = errors,
            TraceId = ResolveTraceId(),
            Timestamp = DateTime.UtcNow
        };

    /// <summary>
    /// 解析当前 TraceId。
    /// </summary>
    /// <returns>当前有效的 TraceId。</returns>
    private static string ResolveTraceId()
    {
        if (!string.IsNullOrWhiteSpace(TraceContext.TraceId))
        {
            return TraceContext.TraceId;
        }

        if (!string.IsNullOrWhiteSpace(TraceContext.TraceId))
        {
            return TraceContext.TraceId;
        }

        if (Activity.Current?.Id is { } id && !string.IsNullOrWhiteSpace(id))
        {
            return id;
        }

        return IdFallbackGenerator.Instance.NextId().ToString();
    }
}

/// <summary>
/// 作为 TraceId 缺失时的本地雪花 ID 备用生成器。
/// </summary>
internal sealed class IdFallbackGenerator
{
    /// <summary>
    /// 延迟初始化的单例实例承载。
    /// </summary>
    private static readonly Lazy<IdFallbackGenerator> Lazy = new(() => new IdFallbackGenerator());

    /// <summary>
    /// 获取备用雪花生成器单例。
    /// </summary>
    public static IdFallbackGenerator Instance => Lazy.Value;

    private readonly object _sync = new();
    private long _lastTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
    private long _sequence;

    private IdFallbackGenerator()
    {
    }

    /// <summary>
    /// 生成雪花风格的本地备用 ID。
    /// </summary>
    /// <returns>本地生成的雪花 ID。</returns>
    public long NextId()
    {
        lock (_sync)
        {
            var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            if (timestamp == _lastTimestamp)
            {
                _sequence = (_sequence + 1) & 4095;
                if (_sequence == 0)
                {
                    timestamp = WaitNextMillis(_lastTimestamp);
                }
            }
            else
            {
                _sequence = 0;
            }

            _lastTimestamp = timestamp;
            return ((timestamp - 1577836800000L) << 22) | _sequence;
        }
    }

    /// <summary>
    /// 等待到下一个毫秒以避免序列冲突。
    /// </summary>
    /// <param name="lastTimestamp">上一毫秒的时间戳。</param>
    /// <returns>下一个时间戳（毫秒）。</returns>
    private static long WaitNextMillis(long lastTimestamp)
    {
        var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        while (timestamp <= lastTimestamp)
        {
            Thread.SpinWait(100);
            timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        }

        return timestamp;
    }
}
