using System;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware;
using ZB.MOM.WW.OtOpcUa.Driver.Historian.Wonderware.Backend;

namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Tests
{
    /// <summary>
    ///     PR C.2 — pins the env-var contract that gates whether the sidecar boots an
    ///     alarm-event writer. Default-on (when the historian itself is enabled) so a
    ///     fresh deploy picks up the writer without a service-config edit; explicit
    ///     <c>false</c> opts a read-only deployment out.
    /// </summary>
    [Trait("Category", "Unit")]
    public sealed class ProgramAlarmWriterTests
    {
        /// <summary>Verifies that BuildAlarmWriter returns a writer when the environment variable is unset.</summary>
        [Fact]
        public void BuildAlarmWriter_returns_writer_when_env_unset()
        {
            using var _ = ScopedEnv("OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED", null);

            var writer = Program.BuildAlarmWriter();

            writer.ShouldNotBeNull();
            writer.ShouldBeOfType<AahClientManagedAlarmEventWriter>();
        }

        /// <summary>Verifies that BuildAlarmWriter returns a writer when the environment variable is explicitly true.</summary>
        /// <param name="value">The truthy environment variable string value to test.</param>
        [Theory]
        [InlineData("true")]
        [InlineData("True")]
        [InlineData("TRUE")]
        public void BuildAlarmWriter_returns_writer_when_env_explicitly_true(string value)
        {
            using var _ = ScopedEnv("OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED", value);

            var writer = Program.BuildAlarmWriter();

            writer.ShouldNotBeNull();
        }

        /// <summary>Verifies that BuildAlarmWriter returns null when the environment variable is false.</summary>
        /// <param name="value">The falsy environment variable string value to test.</param>
        [Theory]
        [InlineData("false")]
        [InlineData("False")]
        [InlineData("FALSE")]
        public void BuildAlarmWriter_returns_null_when_env_false(string value)
        {
            using var _ = ScopedEnv("OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED", value);

            var writer = Program.BuildAlarmWriter();

            writer.ShouldBeNull();
        }

        /// <summary>Verifies that BuildAlarmWriter treats unrecognized values as enabled.</summary>
        [Fact]
        public void BuildAlarmWriter_treats_unrecognized_value_as_enabled()
        {
            // Anything other than the literal "false" (case-insensitive) keeps the writer
            // wired — fail-open under accidental misconfiguration so an alarm-write deploy
            // doesn't silently lose alarms because of a typo.
            using var _ = ScopedEnv("OTOPCUA_HISTORIAN_ALARM_WRITE_ENABLED", "yes");

            var writer = Program.BuildAlarmWriter();

            writer.ShouldNotBeNull();
        }

        private static IDisposable ScopedEnv(string name, string? value)
        {
            var prior = Environment.GetEnvironmentVariable(name);
            Environment.SetEnvironmentVariable(name, value);
            return new DisposableAction(() => Environment.SetEnvironmentVariable(name, prior));
        }

        /// <summary>Disposable wrapper for an action that executes on disposal.</summary>
        private sealed class DisposableAction : IDisposable
        {
            private readonly Action _action;
            /// <summary>Initializes a new instance that will execute the given action on disposal.</summary>
            /// <param name="action">The action to execute when disposed.</param>
            public DisposableAction(Action action) { _action = action; }
            /// <summary>Executes the stored action.</summary>
            public void Dispose() => _action();
        }
    }
}
