using Microsoft.Extensions.ObjectPool;

namespace AyCode.Services.SignalRs;

/// <summary>
/// Request model for tracking pending SignalR requests.
/// Poolable to reduce allocations in high-throughput scenarios.
/// </summary>
public class SignalRRequestModel : IResettable
{
    public DateTime RequestDateTime;
    public DateTime ResponseDateTime;
    public object? ResponseByRequestId;

    public SignalRRequestModel()
    {
        RequestDateTime = DateTime.UtcNow;
    }

    public SignalRRequestModel(object responseByRequestId) : this()
    {
        ResponseByRequestId = responseByRequestId;
    }

    /// <summary>
    /// Resets the model for reuse from the pool.
    /// </summary>
    public bool TryReset()
    {
        RequestDateTime = default;
        ResponseDateTime = default;
        ResponseByRequestId = null;
        return true;
    }

    /// <summary>
    /// Initializes the model with a callback for reuse from the pool.
    /// </summary>
    public void Initialize(object? responseByRequestId = null)
    {
        RequestDateTime = DateTime.UtcNow;
        ResponseDateTime = default;
        ResponseByRequestId = responseByRequestId;
    }
}

/// <summary>
/// Object pool for SignalRRequestModel to reduce allocations.
/// Thread-safe and optimized for concurrent access.
/// </summary>
public static class SignalRRequestModelPool
{
    private static readonly ObjectPool<SignalRRequestModel> Pool = 
        new DefaultObjectPoolProvider().Create<SignalRRequestModel>();

    /// <summary>
    /// Gets a SignalRRequestModel from the pool and initializes it.
    /// </summary>
    public static SignalRRequestModel Get()
    {
        var model = Pool.Get();
        model.Initialize();
        return model;
    }

    /// <summary>
    /// Gets a SignalRRequestModel from the pool and initializes it with a callback.
    /// </summary>
    public static SignalRRequestModel Get(object responseByRequestId)
    {
        var model = Pool.Get();
        model.Initialize(responseByRequestId);
        return model;
    }

    /// <summary>
    /// Returns a SignalRRequestModel to the pool for reuse.
    /// </summary>
    public static void Return(SignalRRequestModel model) => Pool.Return(model);
}