// Copyright 2012-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0

using System.Runtime.InteropServices;
using Shouldly;
using ZB.MOM.NatsNet.Server.Internal;

namespace ZB.MOM.NatsNet.Server.Tests.Internal;

/// <summary>
/// Tests for SignalHandler — mirrors tests from server/signal_test.go.
/// </summary>
public class SignalHandlerTests
{
    /// <summary>
    /// Mirrors CommandToSignal mapping tests.
    /// </summary>
    [Fact] // T:3158
    public void CommandToUnixSignal_ShouldMapCorrectly()
    {
        SignalHandler.CommandToUnixSignal(ServerCommand.Stop).ShouldBe(UnixSignal.SigKill);
        SignalHandler.CommandToUnixSignal(ServerCommand.Quit).ShouldBe(UnixSignal.SigInt);
        SignalHandler.CommandToUnixSignal(ServerCommand.Reopen).ShouldBe(UnixSignal.SigUsr1);
        SignalHandler.CommandToUnixSignal(ServerCommand.Reload).ShouldBe(UnixSignal.SigHup);
    }

    /// <summary>
    /// Mirrors SetProcessName test.
    /// </summary>
    [Fact] // T:3155
    public void SetProcessName_ShouldNotThrow()
    {
        Should.NotThrow(() => SignalHandler.SetProcessName("test-server"));
    }

    /// <summary>
    /// Verify IsWindowsService returns false on non-Windows.
    /// </summary>
    [Fact] // T:3149
    public void IsWindowsService_ShouldReturnFalse()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return; // Skip on Windows
        SignalHandler.IsWindowsService().ShouldBeFalse();
    }

    /// <summary>
    /// Mirrors Run — service.go Run() simply invokes the start function.
    /// </summary>
    [Fact] // T:3148
    public void Run_ShouldInvokeStartAction()
    {
        var called = false;
        SignalHandler.Run(() => called = true);
        called.ShouldBeTrue();
    }

    /// <summary>
    /// ProcessSignal with invalid PID expression should return error.
    /// </summary>
    [Fact] // T:3157
    public void ProcessSignal_InvalidPid_ShouldReturnError()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return; // Skip on Windows

        var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "not-a-pid");
        err.ShouldNotBeNull();
    }

    // ---------------------------------------------------------------------------
    // Tests ported from server/signal_test.go
    // ---------------------------------------------------------------------------

    /// <summary>
    /// Mirrors TestProcessSignalInvalidCommand.
    /// An out-of-range ServerCommand enum value is treated as an unknown signal
    /// and ProcessSignal returns a non-null error.
    /// </summary>
    [Fact] // T:2919
    public void ProcessSignalInvalidCommand_ShouldSucceed()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return; // Skip on Windows

        var err = SignalHandler.ProcessSignal((ServerCommand)99, "123");
        err.ShouldNotBeNull();
    }

    /// <summary>
    /// Mirrors TestProcessSignalInvalidPid.
    /// A non-numeric PID string returns an error containing "invalid pid".
    /// </summary>
    [Fact] // T:2920
    public void ProcessSignalInvalidPid_ShouldSucceed()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return; // Skip on Windows

        var err = SignalHandler.ProcessSignal(ServerCommand.Stop, "abc");
        err.ShouldNotBeNull();
        err!.Message.ShouldContain("invalid pid");
    }

    // ---------------------------------------------------------------------------
    // Deferred signal tests — require pgrep/kill injection or real OS process spawning.
    // These cannot be unit-tested without refactoring SignalHandler to accept
    // injectable pgrep/kill delegates (as the Go source does).
    // ---------------------------------------------------------------------------

    /// <summary>Mirrors TestProcessSignalMultipleProcesses — deferred: requires pgrep injection.</summary>
    [Fact(Skip = "deferred: requires pgrep/kill injection")] // T:2913
    public void ProcessSignalMultipleProcesses_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalMultipleProcessesGlob — deferred: requires pgrep injection.</summary>
    [Fact(Skip = "deferred: requires pgrep/kill injection")] // T:2914
    public void ProcessSignalMultipleProcessesGlob_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalMultipleProcessesGlobPartial — deferred: requires pgrep injection.</summary>
    [Fact(Skip = "deferred: requires pgrep/kill injection")] // T:2915
    public void ProcessSignalMultipleProcessesGlobPartial_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalPgrepError — deferred: requires pgrep injection.</summary>
    [Fact(Skip = "deferred: requires pgrep injection")] // T:2916
    public void ProcessSignalPgrepError_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalPgrepMangled — deferred: requires pgrep injection.</summary>
    [Fact(Skip = "deferred: requires pgrep injection")] // T:2917
    public void ProcessSignalPgrepMangled_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalResolveSingleProcess — deferred: requires pgrep and kill injection.</summary>
    [Fact(Skip = "deferred: requires pgrep/kill injection")] // T:2918
    public void ProcessSignalResolveSingleProcess_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalQuitProcess — deferred: requires kill injection.</summary>
    [Fact(Skip = "deferred: requires kill injection")] // T:2921
    public void ProcessSignalQuitProcess_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalTermProcess — deferred: requires kill injection and commandTerm equivalent.</summary>
    [Fact(Skip = "deferred: requires kill injection")] // T:2922
    public void ProcessSignalTermProcess_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalReopenProcess — deferred: requires kill injection.</summary>
    [Fact(Skip = "deferred: requires kill injection")] // T:2923
    public void ProcessSignalReopenProcess_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalReloadProcess — deferred: requires kill injection.</summary>
    [Fact(Skip = "deferred: requires kill injection")] // T:2924
    public void ProcessSignalReloadProcess_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalLameDuckMode — deferred: requires kill injection and commandLDMode equivalent.</summary>
    [Fact(Skip = "deferred: requires kill injection")] // T:2925
    public void ProcessSignalLameDuckMode_ShouldSucceed() { }

    /// <summary>Mirrors TestProcessSignalTermDuringLameDuckMode — deferred: requires full server (RunServer) and real OS signal.</summary>
    [Fact(Skip = "deferred: requires RunServer and real OS SIGTERM")] // T:2926
    public void ProcessSignalTermDuringLameDuckMode_ShouldSucceed() { }

    /// <summary>Mirrors TestSignalInterruptHasSuccessfulExit — deferred: requires spawning a subprocess to test exit code on SIGINT.</summary>
    [Fact(Skip = "deferred: requires subprocess process spawning")] // T:2927
    public void SignalInterruptHasSuccessfulExit_ShouldSucceed() { }

    /// <summary>Mirrors TestSignalTermHasSuccessfulExit — deferred: requires spawning a subprocess to test exit code on SIGTERM.</summary>
    [Fact(Skip = "deferred: requires subprocess process spawning")] // T:2928
    public void SignalTermHasSuccessfulExit_ShouldSucceed() { }
}
