using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using LibHac.Common;
using Xunit;

namespace LibHac.Tests;

public class BufferStructTests
{
    [Fact]
    public static void BufferIndexer()
    {
        var buffer = new Buffer16();

        buffer[0] = 5;
        buffer[1] = 6;

        Assert.Equal(5, buffer[0]);
        Assert.Equal(6, buffer[1]);
    }

    [Fact]
    public static void CastBufferToByteSpan()
    {
        var buffer = new Buffer16();

        Span<byte> byteSpan = buffer.Bytes;

        Assert.Equal(16, byteSpan.Length);
        Assert.True(Unsafe.AreSame(ref Unsafe.As<Buffer16, byte>(ref buffer), ref byteSpan[0]));
    }

    [Fact]
    public static void CastBufferToByteSpanImplicit()
    {
        var buffer = new Buffer16();

        Span<byte> byteSpan = buffer;

        Assert.Equal(16, byteSpan.Length);
        Assert.True(Unsafe.AreSame(ref Unsafe.As<Buffer16, byte>(ref buffer), ref byteSpan[0]));
    }

    [Fact]
    public static void CastBufferToReadOnlyByteSpanImplicit()
    {
        var buffer = new Buffer16();

        ReadOnlySpan<byte> byteSpan = buffer;

        Assert.Equal(16, byteSpan.Length);
        Assert.True(Unsafe.AreSame(ref Unsafe.As<Buffer16, byte>(ref buffer), ref Unsafe.AsRef(in byteSpan[0])));
    }

    [Fact]
    public static void CastBufferToSpan()
    {
        var buffer = new Buffer16();

        Span<ulong> ulongSpan = buffer.AsSpan<ulong>();

        Assert.Equal(2, ulongSpan.Length);
        Assert.True(Unsafe.AreSame(ref Unsafe.As<Buffer16, ulong>(ref buffer), ref ulongSpan[0]));
    }

    [Fact]
    public static void CastBufferToStruct()
    {
        var buffer = new Buffer16();

        ref ulong ulongSpan = ref buffer.As<ulong>();

        Assert.True(Unsafe.AreSame(ref Unsafe.As<Buffer16, ulong>(ref buffer), ref ulongSpan));
    }

    [Fact]
    public static void CastBufferToLargerStruct()
    {
        var buffer = new Buffer16();

        Assert.Throws<ArgumentException>(() => buffer.As<Struct32Bytes>());
    }

    [StructLayout(LayoutKind.Sequential, Size = 32)]
    private struct Struct32Bytes { }
}