namespace Dada.Supervisor;

internal enum SupervisorState
{
    Starting,
    Ready,
    StartupFailed,
    PortInUse,
    ApiDegraded,
    WorkerDegraded,
    StorageFull,
    StorageUnavailable,
    DiagnosticsRunning,
    DiagnosticsReady,
}

internal enum SupervisorAction
{
    OpenProduct,
    OpenChrome,
    OpenEdge,
    OpenDiagnostics,
    CheckExistingInstance,
    Retry,
    RestartServices,
    Exit,
}

internal static class SupervisorActions
{
    internal static IReadOnlyList<SupervisorAction> For(SupervisorState state) => state switch
    {
        SupervisorState.Starting => [SupervisorAction.OpenDiagnostics, SupervisorAction.Exit],
        SupervisorState.Ready => [SupervisorAction.OpenProduct, SupervisorAction.OpenChrome, SupervisorAction.OpenEdge, SupervisorAction.OpenDiagnostics, SupervisorAction.RestartServices, SupervisorAction.Exit],
        SupervisorState.StartupFailed => [SupervisorAction.Retry, SupervisorAction.OpenDiagnostics, SupervisorAction.Exit],
        SupervisorState.PortInUse => [SupervisorAction.CheckExistingInstance, SupervisorAction.Retry, SupervisorAction.OpenDiagnostics, SupervisorAction.Exit],
        SupervisorState.ApiDegraded => [SupervisorAction.OpenDiagnostics, SupervisorAction.RestartServices, SupervisorAction.Exit],
        SupervisorState.WorkerDegraded => [SupervisorAction.OpenProduct, SupervisorAction.OpenChrome, SupervisorAction.OpenEdge, SupervisorAction.OpenDiagnostics, SupervisorAction.RestartServices, SupervisorAction.Exit],
        SupervisorState.StorageFull => [SupervisorAction.OpenProduct, SupervisorAction.OpenChrome, SupervisorAction.OpenEdge, SupervisorAction.OpenDiagnostics, SupervisorAction.Exit],
        SupervisorState.StorageUnavailable => [SupervisorAction.Retry, SupervisorAction.OpenDiagnostics, SupervisorAction.Exit],
        SupervisorState.DiagnosticsRunning => [SupervisorAction.Exit],
        SupervisorState.DiagnosticsReady => [SupervisorAction.OpenDiagnostics, SupervisorAction.Exit],
        _ => throw new ArgumentOutOfRangeException(nameof(state)),
    };
}

internal static class RestartPolicy
{
    internal const int MaximumRestarts = 3;
    internal static readonly IReadOnlyList<TimeSpan> Delays = [TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(15)];

    internal static bool CanRestart(int completedRestarts, TimeSpan failureWindow) =>
        completedRestarts < MaximumRestarts && failureWindow <= TimeSpan.FromMinutes(5);
}
