using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

public sealed class PendingOrdersCheck
{
    public static readonly ReconciliationCheckType CheckType = ReconciliationCheckType.PendingOrderNoResult;

    private readonly AppDbContext _db;
    private readonly ReconciliationPublisher _publisher;
    private readonly ReconciliationJobOptions _opts;
    private readonly ILogger<PendingOrdersCheck> _logger;

    public PendingOrdersCheck(
        AppDbContext db,
        ReconciliationPublisher publisher,
        IOptions<ReconciliationJobOptions> opts,
        ILogger<PendingOrdersCheck> logger)
    {
        _db        = db;
        _publisher = publisher;
        _opts      = opts.Value;
        _logger    = logger;
    }

    public async Task<int> RunAsync(CancellationToken ct)
    {
        var cutoff = DateTimeOffset.UtcNow
            .AddHours(-_opts.PendingOrderThresholdHours);

        var staleOrders = await _db.Orders
            .Where(o => (o.Status == OrderStatus.Pending || o.Status == OrderStatus.InProgress)
                     && o.OrderedAt < cutoff
                     && o.ResultedAt == null)
            .Select(o => new
            {
                o.Id,
                o.EncounterId,
                o.OrderType,
                o.Description,
                o.OrderedAt,
                PatientId = o.Encounter!.PatientId,
            })
            .ToListAsync(ct);

        if (!staleOrders.Any())
        {
            _logger.LogDebug("[RECONCILIATION] Check2 — no stale pending orders");
            return 0;
        }

        var byEncounter = staleOrders
            .GroupBy(o => new { o.EncounterId, o.PatientId })
            .ToList();

        var inserted = 0;
        foreach (var group in byEncounter)
        {
            var alreadyOpen = await _db.ReconciliationAlerts
                .AnyAsync(r => r.CheckType   == CheckType
                            && r.EncounterId == group.Key.EncounterId
                            && r.ResolvedAt  == null, ct);
            if (alreadyOpen) continue;

            var lines = group.Select(o =>
                $"  [{o.OrderType.ToDbString()}] {o.Description} (ordered {o.OrderedAt:u}, "
              + $"pending {(DateTimeOffset.UtcNow - o.OrderedAt).TotalHours:F1}h) ID={o.Id}");
            var details = $"{group.Count()} order(s) pending without result for encounter "
                        + $"{group.Key.EncounterId}:\n{string.Join("\n", lines)}";

            var rec = new ReconciliationAlert
            {
                Id          = Guid.NewGuid(),
                CheckType   = CheckType,  // ReconciliationCheckType enum
                EncounterId = group.Key.EncounterId,
                PatientId   = group.Key.PatientId,
                Details     = details,
                CreatedAt   = DateTimeOffset.UtcNow,
            };

            _db.ReconciliationAlerts.Add(rec);
            await _db.SaveChangesAsync(ct);
            await _publisher.PublishAsync(rec, ct);

            _logger.LogWarning(
                "[RECONCILIATION] {CheckType} — encounter {EncounterId}: {Count} stale order(s)",
                CheckType, group.Key.EncounterId, group.Count());

            inserted++;
        }

        return inserted;
    }
}