using System.Collections.Concurrent;

namespace NexusShell.Services.Diagnostics;

public sealed record NexusTimerSnapshot(
    string Name,
    string Owner,
    TimeSpan Interval,
    bool UiThread,
    bool IsActive,
    string Description,
    DateTimeOffset RegisteredAtUtc,
    DateTimeOffset? LastUpdatedAtUtc);

public sealed class NexusTimerRegistration : IDisposable
{
    private readonly Action<NexusTimerRegistration> _dispose;
    private bool _disposed;

    internal NexusTimerRegistration(
        string name,
        string owner,
        TimeSpan interval,
        bool uiThread,
        string description,
        Action<NexusTimerRegistration> dispose)
    {
        Name = name;
        Owner = owner;
        Interval = interval;
        UiThread = uiThread;
        Description = description;
        RegisteredAtUtc = DateTimeOffset.UtcNow;
        IsActive = true;
        _dispose = dispose;
    }

    public string Name { get; }
    public string Owner { get; }
    public TimeSpan Interval { get; private set; }
    public bool UiThread { get; }
    public string Description { get; }
    public DateTimeOffset RegisteredAtUtc { get; }
    public DateTimeOffset? LastUpdatedAtUtc { get; private set; }
    public bool IsActive { get; private set; }

    public void UpdateInterval(TimeSpan interval)
    {
        Interval = interval;
        LastUpdatedAtUtc = DateTimeOffset.UtcNow;
    }

    public NexusTimerSnapshot Snapshot() =>
        new(Name, Owner, Interval, UiThread, IsActive, Description, RegisteredAtUtc, LastUpdatedAtUtc);

    public void Dispose()
    {
        if (_disposed)
        {
            return;
        }

        _disposed = true;
        IsActive = false;
        _dispose(this);
    }
}

public static class NexusTimerRegistry
{
    private static readonly ConcurrentDictionary<string, NexusTimerRegistration> Timers = new(StringComparer.OrdinalIgnoreCase);

    public static NexusTimerRegistration Register(
        string name,
        string owner,
        TimeSpan interval,
        bool uiThread,
        string description = "")
    {
        var registration = new NexusTimerRegistration(
            name,
            owner,
            interval,
            uiThread,
            description,
            RemoveRegistration);
        Timers[name] = registration;
        return registration;
    }

    public static IReadOnlyList<NexusTimerSnapshot> Snapshot() =>
        Timers.Values
            .Select(static timer => timer.Snapshot())
            .OrderBy(static timer => timer.Owner, StringComparer.OrdinalIgnoreCase)
            .ThenBy(static timer => timer.Name, StringComparer.OrdinalIgnoreCase)
            .ToList();

    public static void ClearForTests() => Timers.Clear();

    private static void RemoveRegistration(NexusTimerRegistration timer)
    {
        if (Timers.TryGetValue(timer.Name, out var current) && ReferenceEquals(current, timer))
        {
            Timers.TryRemove(timer.Name, out _);
        }
    }
}
