using AyCode.Core.Extensions;
using AyCode.Services.SignalRs;

namespace AyCode.Services.Tests.SignalRs;

[TestClass]
public class PostJsonDataMessageTests
{
    [TestMethod]
    public void SignalParams_SetGet_RoundTrip_ForInt()
    {
        var signalParams = new SignalParams { Status = SignalResponseStatus.Success };
        signalParams.SetParameterValues([42]);

        var paramInfos = typeof(PostJsonDataMessageTests)
            .GetMethod(nameof(DummyIntMethod))!.GetParameters();
        var deserialized = signalParams.GetParameterValues(paramInfos);

        Assert.IsNotNull(deserialized);
        Assert.AreEqual(1, deserialized!.Length);
        Assert.AreEqual(42, deserialized[0]);
    }

    [TestMethod]
    [DataRow(42)]
    [DataRow("45")]
    [DataRow(true)]
    public void SignalParams_FullRoundTrip_AnyParameter(object testValue)
    {
        // Client packs via SetParameterValues
        var signalParams = new SignalParams { Status = SignalResponseStatus.Success };
        signalParams.SetParameterValues([testValue]);

        // Wire round-trip: SignalParams → byte[] → SignalParams
        var wireBytes = signalParams.ToBinary();
        var restored = wireBytes.BinaryTo<SignalParams>()!;

        // Server unpacks via GetParameterValues
        var paramInfos = new[] { GetParamInfoForType(testValue.GetType()) };
        var serverParams = restored.GetParameterValues(paramInfos);

        Assert.IsNotNull(serverParams);
        Assert.AreEqual(testValue, serverParams![0]);

        // Response round-trip — RawResponseData holds the typed object directly (no intermediate byte[])
        var serviceResult = $"{serverParams[0]}";
        var clientResponse = new SignalResponseDataMessage
        {
            MessageTag = 100,
            Status = SignalResponseStatus.Success,
            DataSerializerType = AyCode.Core.Serializers.AcSerializerType.Binary,
            RawResponseData = serviceResult
        };
        var finalResult = clientResponse.GetResponseData<string>();
        Assert.AreEqual(testValue.ToString(), finalResult);
    }

    [TestMethod]
    public void SignalParams_MultipleParams_RoundTrip()
    {
        var guid = Guid.NewGuid();

        var signalParams = new SignalParams { Status = SignalResponseStatus.Success };
        signalParams.SetParameterValues([42, "hello", true, guid]);

        // Wire round-trip
        var wireBytes = signalParams.ToBinary();
        var restored = wireBytes.BinaryTo<SignalParams>()!;

        var paramInfos = typeof(PostJsonDataMessageTests)
            .GetMethod(nameof(DummyMultiMethod))!.GetParameters();
        var deserialized = restored.GetParameterValues(paramInfos);

        Assert.IsNotNull(deserialized);
        Assert.AreEqual(4, deserialized!.Length);
        Assert.AreEqual(42, deserialized[0]);
        Assert.AreEqual("hello", deserialized[1]);
        Assert.AreEqual(true, deserialized[2]);
        Assert.AreEqual(guid, deserialized[3]);
    }

    [TestMethod]
    public void SignalParams_WireFormat_ParametersIsByteArray()
    {
        var signalParams = new SignalParams { Status = SignalResponseStatus.Success };
        signalParams.SetParameterValues([42, "hello"]);

        // Parameters property is byte[] (not byte[][])
        Assert.IsNotNull(signalParams.Parameters);
        Assert.IsInstanceOfType<byte[]>(signalParams.Parameters);
    }

    [TestMethod]
    public void SignalParams_NullParameters_ReturnsNull()
    {
        var signalParams = new SignalParams { Status = SignalResponseStatus.Success };

        var paramInfos = typeof(PostJsonDataMessageTests)
            .GetMethod(nameof(DummyIntMethod))!.GetParameters();
        var result = signalParams.GetParameterValues(paramInfos);

        Assert.IsNull(result);
    }

    // Dummy methods for ParameterInfo extraction
    public static void DummyIntMethod(int value) { }
    public static void DummyMultiMethod(int a, string b, bool c, Guid d) { }
    public static void DummyIntStringMethod(int a, string b) { }

    private static System.Reflection.ParameterInfo GetParamInfoForType(Type type)
    {
        if (type == typeof(int)) return typeof(PostJsonDataMessageTests).GetMethod(nameof(DummyInt))!.GetParameters()[0];
        if (type == typeof(string)) return typeof(PostJsonDataMessageTests).GetMethod(nameof(DummyString))!.GetParameters()[0];
        if (type == typeof(bool)) return typeof(PostJsonDataMessageTests).GetMethod(nameof(DummyBool))!.GetParameters()[0];
        throw new NotSupportedException($"No dummy method for type {type.Name}");
    }

    public static void DummyInt(int v) { }
    public static void DummyString(string v) { }
    public static void DummyBool(bool v) { }
}
