using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;

[Trait("Category", "Unit")]
public sealed class UnsTreeServiceScriptedAlarmTests
{
    private static UnsTreeService SeededService()
    {
        var dbName = $"uns-alarm-{Guid.NewGuid():N}";
        UnsTreeTestDb.SeedNamed(dbName);
        return new UnsTreeService(UnsTreeTestDb.Factory(dbName));
    }

    private static ScriptedAlarmInput Sample(string id = "SA-1") =>
        new(id, "Over-temp", "LimitAlarm", 700, "{TagPath} hot", "SCRIPT-1", HistorizeToAveva: true, Retain: true, Enabled: true);

    [Fact]
    public async Task Create_then_list_and_load_roundtrips()
    {
        var svc = SeededService();
        var create = await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample());
        create.Ok.ShouldBeTrue();
        create.CreatedId.ShouldBe("SA-1");

        var rows = await svc.LoadAlarmsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId);
        rows.Count.ShouldBe(1);
        rows[0].Name.ShouldBe("Over-temp");
        rows[0].Severity.ShouldBe(700);

        var dto = await svc.LoadScriptedAlarmAsync("SA-1");
        dto.ShouldNotBeNull();
        dto!.EquipmentId.ShouldBe(UnsTreeTestDb.SeededEquipmentId);
        dto.HistorizeToAveva.ShouldBeTrue();
        dto.RowVersion.ShouldNotBeNull();
    }

    [Fact]
    public async Task Create_rejects_duplicate_id()
    {
        var svc = SeededService();
        (await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample())).Ok.ShouldBeTrue();
        var dup = await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample());
        dup.Ok.ShouldBeFalse();
        dup.Error.ShouldNotBeNull();
    }

    [Fact]
    public async Task Update_changes_fields()
    {
        var svc = SeededService();
        await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample());
        var dto = await svc.LoadScriptedAlarmAsync("SA-1");

        var upd = await svc.UpdateScriptedAlarmAsync("SA-1",
            Sample() with { Name = "Renamed", Severity = 250, HistorizeToAveva = false }, dto!.RowVersion);
        upd.Ok.ShouldBeTrue();

        var after = await svc.LoadScriptedAlarmAsync("SA-1");
        after!.Name.ShouldBe("Renamed");
        after.Severity.ShouldBe(250);
        after.HistorizeToAveva.ShouldBeFalse();
    }

    [Fact]
    public async Task Delete_removes_row()
    {
        var svc = SeededService();
        await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample());
        var dto = await svc.LoadScriptedAlarmAsync("SA-1");

        (await svc.DeleteScriptedAlarmAsync("SA-1", dto!.RowVersion)).Ok.ShouldBeTrue();
        (await svc.LoadAlarmsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId)).ShouldBeEmpty();
    }

    [Fact]
    public async Task Create_rejects_duplicate_name_on_same_equipment()
    {
        var svc = SeededService();
        (await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-1"))).Ok.ShouldBeTrue();
        // Same Name ("Over-temp" from Sample), different id, same equipment → rejected.
        var dup = await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-2"));
        dup.Ok.ShouldBeFalse();
        dup.Error.ShouldNotBeNull();
        dup.Error!.ShouldContain("already exists");
    }

    [Fact]
    public async Task LoadAlarmsForEquipment_excludes_other_equipment()
    {
        var svc = SeededService();
        await svc.CreateScriptedAlarmAsync(UnsTreeTestDb.SeededEquipmentId, Sample("SA-MINE"));
        await svc.CreateScriptedAlarmAsync("EQ-OTHER", Sample("SA-OTHER") with { Name = "Other-alarm" });

        var rows = await svc.LoadAlarmsForEquipmentAsync(UnsTreeTestDb.SeededEquipmentId);

        rows.Count.ShouldBe(1);
        rows[0].ScriptedAlarmId.ShouldBe("SA-MINE");
    }
}
