using System.Buffers;
using System.Security.Claims;
using AyCode.Core;
using AyCode.Core.Extensions;
using AyCode.Core.Serializers;
using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;
using AyCode.Models.Server.DynamicMethods;
using AyCode.Services.Server.SignalRs;
using AyCode.Services.SignalRs;
using Microsoft.AspNetCore.SignalR.Protocol;
using Microsoft.Extensions.Configuration;

namespace AyCode.Services.Server.Tests.SignalRs;

/// <summary>
/// Testable SignalR hub that overrides infrastructure dependencies.
/// Enables unit testing without SignalR server or mocks.
/// Routes responses through AyCodeBinaryHubProtocol with multi-segment splitting
/// to exercise the full serialization/deserialization pipeline.
/// </summary>
public class TestableSignalRHub2 : AcWebSignalRHubBase<TestSignalRTags, TestLogger>
{
    private IAcSignalRHubItemServer _callerClient;
    private readonly TestMultiSegmentProtocol _protocol;
    private readonly TestInvocationBinder _binder = new();

    #region Test Configuration

    /// <summary>
    /// Simulated connection ID
    /// </summary>
    public string TestConnectionId { get; set; } = "test-connection-id";

    /// <summary>
    /// Simulated user identifier
    /// </summary>
    public string? TestUserIdentifier { get; set; } = "test-user-id";

    /// <summary>
    /// Simulated connection aborted state
    /// </summary>
    public bool TestIsConnectionAborted { get; set; } = false;

    /// <summary>
    /// Simulated ClaimsPrincipal (optional)
    /// </summary>
    public ClaimsPrincipal? TestUser { get; set; }

    #endregion

    public TestableSignalRHub2(BinaryProtocolMode mode = BinaryProtocolMode.Bytes)
        : base(new ConfigurationBuilder().Build(), new TestLogger())
    {
        _protocol = new TestMultiSegmentProtocol(mode);
    }

    public TestableSignalRHub2(IConfiguration configuration, TestLogger logger, BinaryProtocolMode mode = BinaryProtocolMode.Bytes)
        : base(configuration, logger)
    {
        _protocol = new TestMultiSegmentProtocol(mode);
    }

    #region Public Test Entry Points

    /// <summary>
    /// Register a service with SignalR-attributed methods
    /// </summary>
    public void RegisterService(object service, IAcSignalRHubItemServer callerClient)
    {
        _callerClient = callerClient;
        DynamicMethodRegistry.Register(service);
    }

    /// <summary>
    /// Sets the serializer type for testing Binary vs JSON serialization.
    /// </summary>
    public void SetSerializerType(AcSerializerOptions acSerializerOptions)
    {
        SerializerOptions = acSerializerOptions;
    }

    #endregion

    #region Overridden Context Accessors

    protected override string GetConnectionId() => TestConnectionId;

    protected override bool IsConnectionAborted() => TestIsConnectionAborted;

    protected override string? GetUserIdentifier() => TestUserIdentifier;

    protected override ClaimsPrincipal? GetUser() => TestUser;

    #endregion

    #region Overridden Response Methods

    protected override Task ResponseToCaller(int messageTag, SignalResponseStatus status, object? responseData, int? requestId, SignalParams? clientSignalParams = null)
        => SendMessageToClient(_callerClient, messageTag, status, responseData, requestId, clientSignalParams);

    protected override Task SendMessageToClient(IAcSignalRHubItemServer sendTo, int messageTag,
        SignalResponseStatus status, object? responseData, int? requestId = null, SignalParams? clientSignalParams = null)
    {
        var isRawBytes = clientSignalParams?.IsRawBytesData == true;

        if (isRawBytes && responseData != null && responseData is not byte[])
        {
            responseData = SerializerOptions.SerializerType == AcSerializerType.Binary
                ? AcBinarySerializer.Serialize(responseData)
                : AyCode.Core.Compression.GzipHelper.Compress(responseData.ToJson());
        }

        var signalParams = new SignalParams
        {
            Status = status,
            DataSerializerType = SerializerOptions.SerializerType,
            IsRawBytesData = isRawBytes
        };

        //TODO: átrakni a protocl-ra és itt csak beadjuk a protocol-nak! a reader esetbében is olvasáskor!
        // Protocol round-trip: serialize → multi-segment split → deserialize
        var invocation = new InvocationMessage(
            nameof(IAcSignalRHubClient.OnReceiveMessage),
            [messageTag, requestId, signalParams, responseData ?? Array.Empty<byte>()]);

        var bytes = _protocol.GetMessageBytesMultiSegment(invocation);
        var sequence = new ReadOnlySequence<byte>(bytes);
        _protocol.TryParseMessage(ref sequence, _binder, out var parsed);

        var args = ((InvocationMessage)parsed!).Arguments;
        return sendTo.OnReceiveMessage(
            (int)args[0]!, (int?)args[1], (SignalParams)args[2]!, args[3]!);
    }

    #endregion
}
