using System.Security.Claims;
using AyCode.Core.Extensions;
using AyCode.Core.Tests.TestModels;
using AyCode.Models.Server.DynamicMethods;
using AyCode.Services.Server.SignalRs;
using AyCode.Services.SignalRs;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.Configuration;
using Microsoft.VSDiagnostics;

namespace AyCode.Core.Benchmarks;

/// <summary>
/// Benchmarks for SignalR round-trip communication using the same infrastructure as SignalRClientToHubTest.
/// Measures: Client -> Server -> Service -> Response -> Client
/// </summary>
[MemoryDiagnoser]
[CPUUsageDiagnoser]
public class SignalRRoundTripBenchmarks
{
    private BenchmarkSignalRClient _client = null!;
    private BenchmarkSignalRHub _hub = null!;
    private BenchmarkSignalRService _service = null!;
    
    // Pre-created test data
    private TestOrderItem_All_True _testOrderItem = null!;
    private TestOrder_All_True _testOrder = null!;
    private SharedTag_All_True _sharedTag = null!;
    private int[] _intArray = null!;
    private List<string> _stringList = null!;
    private Guid _testGuid;

    [GlobalSetup]
    public void Setup()
    {
        var logger = new TestLogger();
        _hub = new BenchmarkSignalRHub(logger);
        _service = new BenchmarkSignalRService();
        _client = new BenchmarkSignalRClient(_hub, logger);
        _hub.RegisterService(_service, _client);
        
        // Pre-create test data
        _testOrderItem = new TestOrderItem_All_True { Id = 1, ProductName = "Widget", Quantity = 5, UnitPrice = 10.50m };
        _testOrder = TestDataFactory.CreateOrder(itemCount: 3);
        _sharedTag = new SharedTag_All_True { Id = 1, Name = "Important", Color = "#FF0000" };
        _intArray = [1, 2, 3, 4, 5];
        _stringList = ["apple", "banana", "cherry"];
        _testGuid = Guid.NewGuid();
    }

    #region Primitive Parameter Benchmarks

    [Benchmark(Description = "RoundTrip: Single int")]
    [BenchmarkCategory("Primitives")]
    public string? RoundTrip_SingleInt()
    {
        return _client.PostDataSync<int, string>(BenchmarkSignalRTags.SingleIntParam, 42);
    }

    [Benchmark(Description = "RoundTrip: Two ints")]
    [BenchmarkCategory("Primitives")]
    public int RoundTrip_TwoInts()
    {
        return _client.PostSync<int>(BenchmarkSignalRTags.TwoIntParams, [10, 20]);
    }

    [Benchmark(Description = "RoundTrip: Bool")]
    [BenchmarkCategory("Primitives")]
    public bool RoundTrip_Bool()
    {
        return _client.PostDataSync<bool, bool>(BenchmarkSignalRTags.BoolParam, true);
    }

    [Benchmark(Description = "RoundTrip: String")]
    [BenchmarkCategory("Primitives")]
    public string? RoundTrip_String()
    {
        return _client.PostDataSync<string, string>(BenchmarkSignalRTags.StringParam, "Hello");
    }

    [Benchmark(Description = "RoundTrip: Guid")]
    [BenchmarkCategory("Primitives")]
    public Guid RoundTrip_Guid()
    {
        return _client.PostDataSync<Guid, Guid>(BenchmarkSignalRTags.GuidParam, _testGuid);
    }

    [Benchmark(Description = "RoundTrip: No params")]
    [BenchmarkCategory("Primitives")]
    public string? RoundTrip_NoParams()
    {
        return _client.GetAllSync<string>(BenchmarkSignalRTags.NoParams);
    }

    [Benchmark(Description = "RoundTrip: Multiple types (3 params)")]
    [BenchmarkCategory("Primitives")]
    public string? RoundTrip_MultipleTypes()
    {
        return _client.PostSync<string>(BenchmarkSignalRTags.MultipleTypesParams, [true, "test", 42]);
    }

    #endregion

    #region Complex Object Benchmarks

    [Benchmark(Description = "RoundTrip: TestOrderItem_All_True")]
    [BenchmarkCategory("Complex")]
    public TestOrderItem_All_True? RoundTrip_TestOrderItem()
    {
        return _client.PostDataSync<TestOrderItem_All_True, TestOrderItem_All_True>(BenchmarkSignalRTags.TestOrderItemParam, _testOrderItem);
    }

    [Benchmark(Description = "RoundTrip: TestOrder_All_True (3 items)")]
    [BenchmarkCategory("Complex")]
    public TestOrder_All_True? RoundTrip_TestOrder()
    {
        return _client.PostDataSync<TestOrder_All_True, TestOrder_All_True>(BenchmarkSignalRTags.TestOrderParam, _testOrder);
    }

    [Benchmark(Description = "RoundTrip: SharedTag_All_True")]
    [BenchmarkCategory("Complex")]
    public SharedTag_All_True? RoundTrip_SharedTag()
    {
        return _client.PostDataSync<SharedTag_All_True, SharedTag_All_True>(BenchmarkSignalRTags.SharedTagParam, _sharedTag);
    }

    #endregion

    #region Collection Benchmarks

    [Benchmark(Description = "RoundTrip: int[] (5 elements)")]
    [BenchmarkCategory("Collections")]
    public int[]? RoundTrip_IntArray()
    {
        return _client.PostDataSync<int[], int[]>(BenchmarkSignalRTags.IntArrayParam, _intArray);
    }

    [Benchmark(Description = "RoundTrip: List<string> (3 elements)")]
    [BenchmarkCategory("Collections")]
    public List<string>? RoundTrip_StringList()
    {
        return _client.PostDataSync<List<string>, List<string>>(BenchmarkSignalRTags.StringListParam, _stringList);
    }

    #endregion

    #region Mixed Parameter Benchmarks

    [Benchmark(Description = "RoundTrip: Int + DTO")]
    [BenchmarkCategory("Mixed")]
    public string? RoundTrip_IntAndDto()
    {
        return _client.PostSync<string>(BenchmarkSignalRTags.IntAndDtoParam, [42, _testOrderItem]);
    }

    [Benchmark(Description = "RoundTrip: 5 mixed params")]
    [BenchmarkCategory("Mixed")]
    public string? RoundTrip_FiveParams()
    {
        return _client.PostSync<string>(BenchmarkSignalRTags.FiveParams, [42, "hello", true, _testGuid, 99.99m]);
    }

    #endregion
}

#region Benchmark Infrastructure (minimal, reuses production code)

/// <summary>
/// SignalR tags for benchmarks - matches TestSignalRTags structure
/// </summary>
public abstract class BenchmarkSignalRTags : AcSignalRTags
{
    public const int SingleIntParam = 100;
    public const int TwoIntParams = 101;
    public const int BoolParam = 102;
    public const int StringParam = 103;
    public const int GuidParam = 104;
    public const int NoParams = 107;
    public const int MultipleTypesParams = 109;
    public const int TestOrderItemParam = 120;
    public const int TestOrderParam = 121;
    public const int SharedTagParam = 122;
    public const int IntArrayParam = 130;
    public const int StringListParam = 132;
    public const int IntAndDtoParam = 160;
    public const int FiveParams = 164;
}

/// <summary>
/// Benchmark-optimized SignalR client with synchronous methods for accurate timing
/// </summary>
public class BenchmarkSignalRClient : AcSignalRClientBase, IAcSignalRHubItemServer
{
    private readonly BenchmarkSignalRHub _hub;

    public BenchmarkSignalRClient(BenchmarkSignalRHub hub, TestLogger logger) : base(logger)
    {
        _hub = hub;
        // Eliminate polling delay for benchmarks
        MsDelay = 0;
        MsFirstDelay = 0;
    }

    // Synchronous wrappers for benchmarking (avoids async overhead measurement)
    public TResponse? PostDataSync<TPost, TResponse>(int tag, TPost data)
        => PostDataAsync<TPost, TResponse>(tag, data).GetAwaiter().GetResult();

    public TResponse? PostSync<TResponse>(int tag, object[] parameters)
        => PostAsync<TResponse>(tag, parameters).GetAwaiter().GetResult();

    public TResponse? GetAllSync<TResponse>(int tag)
        => GetAllAsync<TResponse>(tag).GetAwaiter().GetResult();

    protected override Task MessageReceived(int messageTag, SignalParams signalParams, object data) => Task.CompletedTask;
    protected override HubConnectionState GetConnectionState() => HubConnectionState.Connected;
    protected override bool IsConnected() => true;
    protected override Task StartConnectionInternal() => Task.CompletedTask;
    protected override Task StopConnectionInternal() => Task.CompletedTask;
    protected override ValueTask DisposeConnectionInternal() => ValueTask.CompletedTask;

    protected override async Task SendToHubAsync(int messageTag, int? requestId, SignalParams signalParams, object? data)
    {
        await _hub.OnReceiveMessage(messageTag, requestId, signalParams, data ?? Array.Empty<byte>());
    }
}

/// <summary>
/// Benchmark-optimized SignalR hub
/// </summary>
public class BenchmarkSignalRHub : AcWebSignalRHubBase<BenchmarkSignalRTags, TestLogger>
{
    private IAcSignalRHubItemServer _callerClient = null!;

    public BenchmarkSignalRHub(TestLogger logger) : base(new ConfigurationBuilder().Build(), logger)
    {
    }

    public void RegisterService(object service, IAcSignalRHubItemServer client)
    {
        _callerClient = client;
        DynamicMethodRegistry.Register(service);
    }

    protected override string GetConnectionId() => "benchmark-connection";
    protected override bool IsConnectionAborted() => false;
    protected override string? GetUserIdentifier() => "benchmark-user";
    protected override ClaimsPrincipal? GetUser() => null;

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

/// <summary>
/// Benchmark service handlers - same logic as TestSignalRService2
/// </summary>
public class BenchmarkSignalRService
{
    [SignalR(BenchmarkSignalRTags.SingleIntParam)]
    public string HandleSingleInt(int value) => $"{value}";

    [SignalR(BenchmarkSignalRTags.TwoIntParams)]
    public int HandleTwoInts(int a, int b) => a + b;

    [SignalR(BenchmarkSignalRTags.BoolParam)]
    public bool HandleBool(bool value) => value;

    [SignalR(BenchmarkSignalRTags.StringParam)]
    public string HandleString(string text) => $"Echo: {text}";

    [SignalR(BenchmarkSignalRTags.GuidParam)]
    public Guid HandleGuid(Guid id) => id;

    [SignalR(BenchmarkSignalRTags.NoParams)]
    public string HandleNoParams() => "OK";

    [SignalR(BenchmarkSignalRTags.MultipleTypesParams)]
    public string HandleMultipleTypes(bool flag, string text, int number) => $"{flag}-{text}-{number}";

    [SignalR(BenchmarkSignalRTags.TestOrderItemParam)]
    public TestOrderItem_All_True HandleTestOrderItem(TestOrderItem_All_True item) => new()
    {
        Id = item.Id,
        ProductName = $"Processed: {item.ProductName}",
        Quantity = item.Quantity * 2,
        UnitPrice = item.UnitPrice * 2,
    };

    [SignalR(BenchmarkSignalRTags.TestOrderParam)]
    public TestOrder_All_True HandleTestOrder(TestOrder_All_True order) => order;

    [SignalR(BenchmarkSignalRTags.SharedTagParam)]
    public SharedTag_All_True HandleSharedTag(SharedTag_All_True tag) => tag;

    [SignalR(BenchmarkSignalRTags.IntArrayParam)]
    public int[] HandleIntArray(int[] values) => values.Select(x => x * 2).ToArray();

    [SignalR(BenchmarkSignalRTags.StringListParam)]
    public List<string> HandleStringList(List<string> items) => items.Select(x => x.ToUpper()).ToList();

    [SignalR(BenchmarkSignalRTags.IntAndDtoParam)]
    public string HandleIntAndDto(int id, TestOrderItem_All_True item) => $"{id}-{item?.ProductName}";

    [SignalR(BenchmarkSignalRTags.FiveParams)]
    public string HandleFiveParams(int a, string b, bool c, Guid d, decimal e) => $"{a}-{b}-{c}-{d}-{e}";
}

#endregion
