using Microsoft.AspNetCore.Http;
using NATS.Server.Subscriptions;

namespace NATS.Server.Monitoring;

/// <summary>
/// Handles /subz endpoint requests, returning subscription information.
/// Corresponds to Go server/monitor.go handleSubsz.
/// </summary>
public sealed class SubszHandler(NatsServer server)
{
    public Subsz HandleSubsz(HttpContext ctx)
    {
        var opts = ParseQueryParams(ctx);
        var now = DateTime.UtcNow;

        // Collect subscriptions from all accounts (or filtered).
        // Exclude the $SYS system account unless explicitly requested — its internal
        // subscriptions are infrastructure and not user-facing.
        var allSubs = new List<Subscription>();
        foreach (var account in server.GetAccounts())
        {
            if (!string.IsNullOrEmpty(opts.Account) && account.Name != opts.Account)
                continue;
            if (string.IsNullOrEmpty(opts.Account) && account.Name == "$SYS")
                continue;
            allSubs.AddRange(account.SubList.GetAllSubscriptions());
        }

        // Filter by test subject if provided
        if (!string.IsNullOrEmpty(opts.Test))
        {
            allSubs = allSubs.Where(s => SubjectMatch.MatchLiteral(opts.Test, s.Subject)).ToList();
        }

        var total = allSubs.Count;
        var numSubs = server.GetAccounts()
            .Where(a => (string.IsNullOrEmpty(opts.Account) && a.Name != "$SYS") || a.Name == opts.Account)
            .Aggregate(0u, (sum, a) => sum + a.SubList.Count);
        var numCache = server.GetAccounts()
            .Where(a => (string.IsNullOrEmpty(opts.Account) && a.Name != "$SYS") || a.Name == opts.Account)
            .Sum(a => a.SubList.CacheCount);

        SubDetail[] details = [];
        if (opts.Subscriptions)
        {
            details = allSubs
                .Skip(opts.Offset)
                .Take(opts.Limit)
                .Select(s => new SubDetail
                {
                    Subject = s.Subject,
                    Queue = s.Queue ?? "",
                    Sid = s.Sid,
                    Msgs = Interlocked.Read(ref s.MessageCount),
                    Max = s.MaxMessages,
                    Cid = s.Client?.Id ?? 0,
                })
                .ToArray();
        }

        return new Subsz
        {
            Id = server.ServerId,
            Now = now,
            NumSubs = numSubs,
            NumCache = numCache,
            Total = total,
            Offset = opts.Offset,
            Limit = opts.Limit,
            Subs = details,
        };
    }

    private static SubszOptions ParseQueryParams(HttpContext ctx)
    {
        var q = ctx.Request.Query;
        var opts = new SubszOptions();

        if (q.TryGetValue("subs", out var subs))
            opts.Subscriptions = subs == "true" || subs == "1" || subs == "detail";

        if (q.TryGetValue("offset", out var offset) && int.TryParse(offset, out var o))
            opts.Offset = o;

        if (q.TryGetValue("limit", out var limit) && int.TryParse(limit, out var l))
            opts.Limit = l;

        if (q.TryGetValue("acc", out var acc))
            opts.Account = acc.ToString();

        if (q.TryGetValue("test", out var test))
            opts.Test = test.ToString();

        return opts;
    }
}
