using BenchmarkDotNet.Attributes;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Microsoft.VSDiagnostics;

namespace AyCode.Benchmark;
[CPUUsageDiagnoser]
public class RefForeachBenchmark
{
    // Simulates BinaryPropertyAccessor (large struct ~80 bytes)
    public struct PropertyAccessor
    {
        public int PropertyIndex;
        public TypeCode PropertyTypeCode;
        public int AccessorType;
        public long Field1, Field2, Field3, Field4, Field5, Field6, Field7, Field8;
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public readonly int GetValue() => PropertyIndex + (int)PropertyTypeCode + AccessorType;
    }

    private PropertyAccessor[] _properties = null !;
    private List<PropertyAccessor> _propertiesList = null !;
    [GlobalSetup]
    public void Setup()
    {
        _properties = new PropertyAccessor[20]; // Typical property count
        _propertiesList = new List<PropertyAccessor>(20);
        for (int i = 0; i < 20; i++)
        {
            var prop = new PropertyAccessor
            {
                PropertyIndex = i,
                PropertyTypeCode = TypeCode.Int32,
                AccessorType = i % 5,
                Field1 = i,
                Field2 = i,
                Field3 = i,
                Field4 = i,
                Field5 = i,
                Field6 = i,
                Field7 = i,
                Field8 = i
            };
            _properties[i] = prop;
            _propertiesList.Add(prop);
        }
    }

    // ============ ARRAY ITERATION ============
    [Benchmark(Baseline = true)]
    public int Array_ForEach_ByValue()
    {
        int total = 0;
        for (int iter = 0; iter < 1000; iter++)
        {
            foreach (var prop in _properties)
            {
                total += prop.GetValue();
            }
        }

        return total;
    }

    [Benchmark]
    public int Array_ForEach_RefReadonly()
    {
        int total = 0;
        for (int iter = 0; iter < 1000; iter++)
        {
            foreach (ref readonly var prop in _properties.AsSpan())
            {
                total += prop.GetValue();
            }
        }

        return total;
    }

    [Benchmark]
    public int Array_ForLoop_Index()
    {
        int total = 0;
        var props = _properties;
        for (int iter = 0; iter < 1000; iter++)
        {
            for (int i = 0; i < props.Length; i++)
            {
                total += props[i].GetValue();
            }
        }

        return total;
    }

    [Benchmark]
    public int Array_ForLoop_Span()
    {
        int total = 0;
        for (int iter = 0; iter < 1000; iter++)
        {
            var span = _properties.AsSpan();
            for (int i = 0; i < span.Length; i++)
            {
                total += span[i].GetValue();
            }
        }

        return total;
    }

    // ============ LIST ITERATION ============
    [Benchmark]
    public int List_ForEach_ByValue()
    {
        int total = 0;
        for (int iter = 0; iter < 1000; iter++)
        {
            foreach (var prop in _propertiesList)
            {
                total += prop.GetValue();
            }
        }

        return total;
    }

    [Benchmark]
    public int List_CollectionsMarshal_RefReadonly()
    {
        int total = 0;
        for (int iter = 0; iter < 1000; iter++)
        {
            foreach (ref readonly var prop in CollectionsMarshal.AsSpan(_propertiesList))
            {
                total += prop.GetValue();
            }
        }

        return total;
    }

    [Benchmark]
    public int List_ForLoop_Index()
    {
        int total = 0;
        var props = _propertiesList;
        for (int iter = 0; iter < 1000; iter++)
        {
            for (int i = 0; i < props.Count; i++)
            {
                total += props[i].GetValue();
            }
        }

        return total;
    }
}