using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
using ZB.MOM.WW.OtOpcUa.Core.AlarmHistorian;
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Proxy.Ipc;
using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Contracts;

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

/// <summary>
///     Phase 7 follow-up #247 — covers the wire-format translation between the
///     <see cref="AlarmHistorianEvent"/> the SQLite sink hands to the writer + the
///     <see cref="HistorianAlarmEventDto"/> the Galaxy.Host IPC contract expects, plus
///     the per-event outcome enum mapping. Pure functions; the round-trip over a real
///     pipe is exercised by the live Host suite (task #240).
/// </summary>
[Trait("Category", "Unit")]
public sealed class GalaxyHistorianWriterMappingTests
{
    [Fact]
    public void ToDto_round_trips_every_field()
    {
        var ts = new DateTime(2026, 4, 20, 14, 30, 0, DateTimeKind.Utc);
        var e = new AlarmHistorianEvent(
            AlarmId: "al-7",
            EquipmentPath: "/Site/Line/Cell",
            AlarmName: "HighTemp",
            AlarmTypeName: "LimitAlarm",
            Severity: AlarmSeverity.High,
            EventKind: "RaiseEvent",
            Message: "Temp 92°C exceeded 90°C",
            User: "operator-7",
            Comment: "ack with reason",
            TimestampUtc: ts);

        var dto = GalaxyHistorianWriter.ToDto(e);

        dto.AlarmId.ShouldBe("al-7");
        dto.EquipmentPath.ShouldBe("/Site/Line/Cell");
        dto.AlarmName.ShouldBe("HighTemp");
        dto.AlarmTypeName.ShouldBe("LimitAlarm");
        dto.Severity.ShouldBe((int)AlarmSeverity.High);
        dto.EventKind.ShouldBe("RaiseEvent");
        dto.Message.ShouldBe("Temp 92°C exceeded 90°C");
        dto.User.ShouldBe("operator-7");
        dto.Comment.ShouldBe("ack with reason");
        dto.TimestampUtcUnixMs.ShouldBe(new DateTimeOffset(ts, TimeSpan.Zero).ToUnixTimeMilliseconds());
    }

    [Fact]
    public void ToDto_preserves_null_Comment()
    {
        var e = new AlarmHistorianEvent(
            "a", "/p", "n", "AlarmCondition", AlarmSeverity.Low, "RaiseEvent", "m",
            User: "system", Comment: null, TimestampUtc: DateTime.UtcNow);

        GalaxyHistorianWriter.ToDto(e).Comment.ShouldBeNull();
    }

    [Theory]
    [InlineData(HistorianAlarmEventOutcomeDto.Ack, HistorianWriteOutcome.Ack)]
    [InlineData(HistorianAlarmEventOutcomeDto.RetryPlease, HistorianWriteOutcome.RetryPlease)]
    [InlineData(HistorianAlarmEventOutcomeDto.PermanentFail, HistorianWriteOutcome.PermanentFail)]
    public void MapOutcome_round_trips_every_byte(
        HistorianAlarmEventOutcomeDto wire, HistorianWriteOutcome expected)
    {
        GalaxyHistorianWriter.MapOutcome(wire).ShouldBe(expected);
    }

    [Fact]
    public void MapOutcome_unknown_byte_throws()
    {
        Should.Throw<InvalidOperationException>(
            () => GalaxyHistorianWriter.MapOutcome((HistorianAlarmEventOutcomeDto)0xFF));
    }

    [Fact]
    public void Null_client_rejected()
    {
        Should.Throw<ArgumentNullException>(() => new GalaxyHistorianWriter(null!));
    }

}
