using Microsoft.Extensions.Logging;
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;

namespace ZB.MOM.WW.OtOpcUa.Core.Stability;

/// <summary>
///     Tier C only process-recycle companion to <see cref="MemoryTracking"/>. On a
///     <see cref="MemoryTrackingAction.HardBreach"/> signal, invokes the supplied
///     <see cref="IDriverSupervisor"/> to restart the out-of-process Host.
/// </summary>
/// <remarks>
///     Per <c>docs/v2/plan.md</c>. Tier A/B hard-breach on an in-process
///     driver would kill every OPC UA session and every co-hosted driver, so for Tier A/B this
///     class logs a <b>promotion-to-Tier-C recommendation</b> and does NOT invoke any supervisor.
///     A future tier-migration workflow acts on the recommendation.
/// </remarks>
public sealed class MemoryRecycle
{
    private readonly DriverTier _tier;
    private readonly IDriverSupervisor? _supervisor;
    private readonly ILogger<MemoryRecycle> _logger;

    /// <summary>Initializes a new instance of the <see cref="MemoryRecycle"/> class.</summary>
    /// <param name="tier">The driver tier.</param>
    /// <param name="supervisor">Optional supervisor for process recycling.</param>
    /// <param name="logger">Logger for recycling events.</param>
    public MemoryRecycle(DriverTier tier, IDriverSupervisor? supervisor, ILogger<MemoryRecycle> logger)
    {
        _tier = tier;
        _supervisor = supervisor;
        _logger = logger;
    }

    /// <summary>
    ///     Handle a <see cref="MemoryTracking"/> classification for the driver. For Tier C with a
    ///     wired supervisor, <c>HardBreach</c> triggers <see cref="IDriverSupervisor.RecycleAsync"/>.
    ///     All other combinations are no-ops with respect to process state (soft breaches + Tier A/B
    ///     hard breaches just log).
    /// </summary>
    /// <param name="action">The memory tracking action.</param>
    /// <param name="footprintBytes">The current process footprint in bytes.</param>
    /// <param name="cancellationToken">Cancellation token for the operation.</param>
    /// <returns>True when a recycle was requested; false otherwise.</returns>
    public async Task<bool> HandleAsync(MemoryTrackingAction action, long footprintBytes, CancellationToken cancellationToken)
    {
        switch (action)
        {
            case MemoryTrackingAction.SoftBreach:
                _logger.LogWarning(
                    "Memory soft-breach on driver {DriverId}: footprint={Footprint:N0} bytes, tier={Tier}. Surfaced to Admin; no action.",
                    _supervisor?.DriverInstanceId ?? "(unknown)", footprintBytes, _tier);
                return false;

            case MemoryTrackingAction.HardBreach when _tier == DriverTier.C && _supervisor is not null:
                _logger.LogError(
                    "Memory hard-breach on Tier C driver {DriverId}: footprint={Footprint:N0} bytes. Requesting supervisor recycle.",
                    _supervisor.DriverInstanceId, footprintBytes);
                await _supervisor.RecycleAsync($"Memory hard-breach: {footprintBytes} bytes", cancellationToken).ConfigureAwait(false);
                return true;

            case MemoryTrackingAction.HardBreach:
                _logger.LogError(
                    "Memory hard-breach on Tier {Tier} in-process driver {DriverId}: footprint={Footprint:N0} bytes. " +
                    "Recommending promotion to Tier C; NOT auto-killing (decisions #74, #145).",
                    _tier, _supervisor?.DriverInstanceId ?? "(unknown)", footprintBytes);
                return false;

            default:
                return false;
        }
    }
}
