using AyCode.Core.Serializers.Binaries;
using AyCode.Core.Tests.TestModels;

namespace AyCode.Core.Tests.Serialization;

[TestClass]
public class AcBinarySerializerBenchmarkTests
{
    [TestMethod]
    public void Serialize_BenchmarkOrder_RoundTrip()
    {
        var order = TestDataFactory.CreateBenchmarkOrder(itemCount: 3, palletsPerItem: 2, measurementsPerPallet: 2, pointsPerMeasurement: 5);

        var binary = AcBinarySerializer.Serialize(order);
        Assert.IsTrue(binary.Length > 0, "Binary data should not be empty");

        var result = AcBinaryDeserializer.Deserialize<TestOrder_All_True>(binary);
        Assert.IsNotNull(result);
        Assert.AreEqual(order.Id, result.Id);
        Assert.AreEqual(order.OrderNumber, result.OrderNumber);
        Assert.AreEqual(order.Items.Count, result.Items.Count);
    }

    [TestMethod]
    public void Serialize_BenchmarkOrder_SmallData_RoundTrip()
    {
        var order = TestDataFactory.CreateBenchmarkOrder(itemCount: 1, palletsPerItem: 1, measurementsPerPallet: 1, pointsPerMeasurement: 1);

        var binary = AcBinarySerializer.Serialize(order);
        Assert.IsTrue(binary.Length > 0);

        var result = AcBinaryDeserializer.Deserialize<TestOrder_All_True>(binary);
        Assert.IsNotNull(result);
        Assert.AreEqual(order.Id, result.Id);
    }

    [TestMethod]
    public void Serialize_BenchmarkOrder_LargeData_RoundTrip()
    {
        var order = TestDataFactory.CreateBenchmarkOrder(itemCount: 10, palletsPerItem: 5, measurementsPerPallet: 3, pointsPerMeasurement: 10);

        var binary = AcBinarySerializer.Serialize(order);
        Assert.IsTrue(binary.Length > 0, "Binary data should not be empty");

        var result = AcBinaryDeserializer.Deserialize<TestOrder_All_True>(binary);
        Assert.IsNotNull(result);
        Assert.AreEqual(order.Id, result.Id);
        Assert.AreEqual(order.OrderNumber, result.OrderNumber);
        Assert.AreEqual(order.Items.Count, result.Items.Count);

        // Verify nested structure
        for (int i = 0; i < order.Items.Count; i++)
        {
            Assert.AreEqual(order.Items[i].Id, result.Items[i].Id);
            Assert.AreEqual(order.Items[i].Pallets.Count, result.Items[i].Pallets.Count);
        }
    }

    [TestMethod]
    public void Serialize_BenchmarkOrder_WithStringInterning_SmallerThanWithout()
    {
        var order = TestDataFactory.CreateBenchmarkOrder(itemCount: 5, palletsPerItem: 3, measurementsPerPallet: 2, pointsPerMeasurement: 5);

        var binaryWithInterning = AcBinarySerializer.Serialize(order, AcBinarySerializerOptions.Default);
        var binaryWithoutInterning = AcBinarySerializer.Serialize(order, new AcBinarySerializerOptions { UseStringInterning = StringInterningMode.None });

        // Note: String interning may not always result in smaller size due to header overhead
        // The primary benefit is for larger datasets with many repeated strings
        Console.WriteLine($"With interning: {binaryWithInterning.Length}, Without: {binaryWithoutInterning.Length}");

        // Both should deserialize correctly regardless of size
        var result1 = AcBinaryDeserializer.Deserialize<TestOrder_All_True>(binaryWithInterning);
        var result2 = AcBinaryDeserializer.Deserialize<TestOrder_All_True>(binaryWithoutInterning);

        Assert.IsNotNull(result1);
        Assert.IsNotNull(result2);
        Assert.AreEqual(order.Id, result1.Id);
        Assert.AreEqual(order.Id, result2.Id);
        Assert.AreEqual(order.Items.Count, result1.Items.Count);
        Assert.AreEqual(order.Items.Count, result2.Items.Count);
    }
}
