using AyCode.Core.Tests.TestModels;
using AyCode.Services.Server.SignalRs;
using AyCode.Services.Server.Tests.SignalRs;

namespace AyCode.Services.Server.Tests;

[TestClass]
public class InvokeMethodExtensionTests
{
        #region InvokeMethod Unit Tests

    [TestMethod]
    public void InvokeMethod_SyncMethod_ReturnsValue()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleSingleInt")!;
        
        var result = methodInfo.InvokeMethod(service, 42);
        
        Assert.AreEqual("42", result);
    }

    [TestMethod]
    public void InvokeMethod_AsyncTaskTMethod_ReturnsUnwrappedValue()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleAsyncString")!;
        
        var result = methodInfo.InvokeMethod(service, "Test");
        
        Assert.IsNotNull(result, "InvokeMethod should unwrap Task<T> and return the result");
        Assert.AreEqual("Async: Test", result);
    }

    [TestMethod]
    public void InvokeMethod_AsyncTaskTMethod_WithComplexObject_ReturnsUnwrappedValue()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleAsyncTestOrderItem")!;
        var input = new TestOrderItem_All_True { Id = 1, ProductName = "Widget", Quantity = 5, UnitPrice = 10m };
        
        var result = methodInfo.InvokeMethod(service, input);
        
        Assert.IsNotNull(result, "InvokeMethod should unwrap Task<TestOrderItem_All_True> and return the result");
        Assert.IsInstanceOfType(result, typeof(TestOrderItem_All_True));
        var item = (TestOrderItem_All_True)result;
        Assert.AreEqual("Async: Widget", item.ProductName);
        Assert.AreEqual(15, item.Quantity);
    }

    [TestMethod]
    public void InvokeMethod_AsyncTaskTMethod_WithInt_ReturnsUnwrappedValue()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleAsyncInt")!;
        
        var result = methodInfo.InvokeMethod(service, 42);
        
        Assert.IsNotNull(result, "InvokeMethod should unwrap Task<int> and return the result");
        Assert.AreEqual(84, result);
    }

    /// <summary>
    /// CRITICAL: Tests Task.FromResult() - methods returning Task without async keyword.
    /// This was the root cause of the production bug where Task wrapper was serialized.
    /// </summary>
    [TestMethod]
    public void InvokeMethod_TaskFromResult_ReturnsUnwrappedValue()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultString")!;
        
        var result = methodInfo.InvokeMethod(service, "Test");
        
        Assert.IsNotNull(result, "InvokeMethod should unwrap Task.FromResult<T> and return the result");
        Assert.AreEqual("FromResult: Test", result);
    }

    [TestMethod]
    public void InvokeMethod_TaskFromResult_WithComplexObject_ReturnsUnwrappedValue()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultTestOrderItem")!;
        var input = new TestOrderItem_All_True { Id = 1, ProductName = "Widget", Quantity = 5, UnitPrice = 10m };
        
        var result = methodInfo.InvokeMethod(service, input);
        
        Assert.IsNotNull(result, "InvokeMethod should unwrap Task.FromResult<TestOrderItem_All_True> and return the result");
        Assert.IsInstanceOfType(result, typeof(TestOrderItem_All_True));
        var item = (TestOrderItem_All_True)result;
        Assert.AreEqual("FromResult: Widget", item.ProductName);
        Assert.AreEqual(10, item.Quantity); // Doubled
    }

    [TestMethod]
    public void InvokeMethod_TaskFromResult_WithInt_ReturnsUnwrappedValue()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultInt")!;
        
        var result = methodInfo.InvokeMethod(service, 42);
        
        Assert.IsNotNull(result, "InvokeMethod should unwrap Task.FromResult<int> and return the result");
        Assert.AreEqual(84, result);
    }

    [TestMethod]
    public void InvokeMethod_NonGenericTask_ReturnsNull()
    {
        var service = new TestSignalRService2();
        var methodInfo = typeof(TestSignalRService2).GetMethod("HandleTaskFromResultNoParams")!;
        
        var result = methodInfo.InvokeMethod(service);
        
        // Task.CompletedTask returns a completed Task, InvokeMethod waits for it
        // The result should be null since it's a non-generic Task (no return value)
        // Note: Task.CompletedTask internally may be Task<VoidTaskResult> but we don't expose it
        // The important thing is the method completes without exception
    }

    #endregion
}