using Inspectron.Epson;
using Inspectron.Epson.PrintServer.Telemetry;

namespace EpsonPrintService;

public sealed class InsinTelemetryDiscoveredPrintersReceiver : IDiscoveredPrintersReceiver
{
    private readonly IDiscoveredPrintersReceiver _inner;
    private readonly IInsinTelemetry _telemetry;
    private readonly HashSet<string> _seenIps = new();
    private readonly Dictionary<string, bool> _present = new();
    private readonly object _stateLock = new();

    public InsinTelemetryDiscoveredPrintersReceiver(
        IDiscoveredPrintersReceiver inner,
        IInsinTelemetry telemetry)
    {
        _inner = inner;
        _telemetry = telemetry;
    }

    public async Task OnPrintersDiscoveredAsync(IReadOnlyList<DiscoveredPrinter> printers)
    {
        await _inner.OnPrintersDiscoveredAsync(printers);

        List<(string kind, string message)> toEmit;
        lock (_stateLock)
        {
            toEmit = ComputeEvents(printers);
        }

        foreach (var (kind, message) in toEmit)
        {
            try { _telemetry.Emit(kind, message); }
            catch { /* swallow: telemetry must never break discovery */ }
        }
    }

    private List<(string, string)> ComputeEvents(IReadOnlyList<DiscoveredPrinter> printers)
    {
        var events = new List<(string, string)>();
        var currentIps = new HashSet<string>();
        foreach (var p in printers)
        {
            if (string.IsNullOrEmpty(p.IPAddress)) continue;
            currentIps.Add(p.IPAddress);

            if (_seenIps.Add(p.IPAddress))
                events.Add((InsinEventKinds.PrinterDiscovered,
                    InsinMessageFormatter.Format(("printer", p.IPAddress), ("model", p.ModelName))));

            if (!_present.TryGetValue(p.IPAddress, out var wasPresent) || !wasPresent)
                events.Add((InsinEventKinds.PrinterOnline,
                    InsinMessageFormatter.Format(("printer", p.IPAddress))));

            _present[p.IPAddress] = true;
        }

        foreach (var kv in _present.ToList())
        {
            if (kv.Value && !currentIps.Contains(kv.Key))
            {
                events.Add((InsinEventKinds.PrinterOffline,
                    InsinMessageFormatter.Format(("printer", kv.Key))));
                _present[kv.Key] = false;
            }
        }

        return events;
    }
}
