using System;
using System.IO;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Stability;

namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Tests;

[Trait("Category", "Unit")]
public sealed class PostMortemMmfTests : IDisposable
{
    private readonly string _path = Path.Combine(Path.GetTempPath(), $"mmf-test-{Guid.NewGuid():N}.bin");

    public void Dispose()
    {
        if (File.Exists(_path)) File.Delete(_path);
    }

    [Fact]
    public void Write_then_read_round_trips_entries_in_oldest_first_order()
    {
        using (var mmf = new PostMortemMmf(_path, capacity: 10))
        {
            mmf.Write(0x30, "read tag-1");
            mmf.Write(0x30, "read tag-2");
            mmf.Write(0x32, "write tag-3");
        }

        using var reopen = new PostMortemMmf(_path, capacity: 10);
        var entries = reopen.ReadAll();
        entries.Length.ShouldBe(3);
        entries[0].Message.ShouldBe("read tag-1");
        entries[1].Message.ShouldBe("read tag-2");
        entries[2].Message.ShouldBe("write tag-3");
        entries[0].OpKind.ShouldBe(0x30L);
    }

    [Fact]
    public void Ring_buffer_wraps_and_oldest_entry_is_overwritten()
    {
        using var mmf = new PostMortemMmf(_path, capacity: 3);
        mmf.Write(1, "A");
        mmf.Write(2, "B");
        mmf.Write(3, "C");
        mmf.Write(4, "D"); // overwrites A

        var entries = mmf.ReadAll();
        entries.Length.ShouldBe(3);
        entries[0].Message.ShouldBe("B");
        entries[1].Message.ShouldBe("C");
        entries[2].Message.ShouldBe("D");
    }

    [Fact]
    public void Message_longer_than_capacity_is_truncated_safely()
    {
        using var mmf = new PostMortemMmf(_path, capacity: 2);
        var huge = new string('x', 500);
        mmf.Write(0, huge);

        var entries = mmf.ReadAll();
        entries[0].Message.Length.ShouldBeLessThan(PostMortemMmf.EntryBytes);
    }
}
