using Microsoft.EntityFrameworkCore;

public class DigitizationHistoryService : IDigitizationHistoryService
{
    private readonly AppDbContext _db;

    public DigitizationHistoryService(AppDbContext db)
    {
        _db = db;
    }

    public async Task<PatientDigitizationHistoryResponse> GetPatientHistoryAsync(Guid patientId)
    {
        // Verify the patient exists (has at least one batch)
        var hasBatches = await _db.DigitizationBatches
            .AnyAsync(b => b.PatientId == patientId);

        if (!hasBatches)
            throw new NotFoundException(
                $"No digitization history found for patient {patientId}.",
                "PATIENT_HISTORY_NOT_FOUND");

        // Load all batches for this patient with their relationships
        var batches = await _db.DigitizationBatches
            .Include(b => b.DraftObservations)
            .Include(b => b.Events)
                .ThenInclude(e => e.Actor)
            .Include(b => b.EnteredByUser)
            .Include(b => b.VerifiedByUser)
            .Include(b => b.ApprovedByUser)
            .Where(b => b.PatientId == patientId)
            .OrderByDescending(b => b.CreatedAt)
            .ToListAsync();

        // For each promoted batch, count live vs superseded observations
        var promotedBatchIds = batches
            .Where(b => b.Status == BatchStatus.Promoted)
            .Select(b => b.Id)
            .ToList();

        var liveObservationCounts = await _db.LiveObservations
            .Where(o => promotedBatchIds.Contains(o.SourceBatchId))
            .GroupBy(o => new { o.SourceBatchId, o.IsSuperseded })
            .Select(g => new
            {
                g.Key.SourceBatchId,
                g.Key.IsSuperseded,
                Count = g.Count()
            })
            .ToListAsync();

        // Build a lookup: batchId -> (activeCount, supersededCount)
        var obsCountLookup = promotedBatchIds.ToDictionary(
            id => id,
            id =>
            {
                var active = liveObservationCounts
                    .FirstOrDefault(x => x.SourceBatchId == id && !x.IsSuperseded)?.Count ?? 0;
                var superseded = liveObservationCounts
                    .FirstOrDefault(x => x.SourceBatchId == id && x.IsSuperseded)?.Count ?? 0;
                return (Active: active, Superseded: superseded);
            });

        // Build a lookup for "has been superseded" — batches that appear as
        // SupersedesBatchId on another batch that reached Promoted
        var supersededByLookup = await _db.DigitizationBatches
            .Where(b => b.SupersedesBatchId.HasValue
                     && b.Status == BatchStatus.Promoted
                     && promotedBatchIds.Contains(b.SupersedesBatchId.Value))
            .ToDictionaryAsync(
                b => b.SupersedesBatchId!.Value,
                b => b.Id);

        var entries = batches.Select(b =>
        {
            var counts = obsCountLookup.GetValueOrDefault(b.Id, (Active: 0, Superseded: 0));
            var hasBeenSuperseded = supersededByLookup.ContainsKey(b.Id);
            supersededByLookup.TryGetValue(b.Id, out var supersededByBatchId);

            return new DigitizationHistoryEntry(
                BatchId: b.Id,
                Status: b.Status.ToDbString(),
                BatchType: b.BatchType.ToDbString(),
                Track: b.Track.ToDbString(),
                SupersedesBatchId: b.SupersedesBatchId,
                IsCorrection: b.SupersedesBatchId.HasValue,
                HasBeenSuperseded: hasBeenSuperseded,
                SupersededByBatchId: hasBeenSuperseded ? supersededByBatchId : null,
                DraftObservationCount: b.DraftObservations.Count,
                LiveObservationCount: counts.Active,
                SupersededObservationCount: counts.Superseded,
                CreatedAt: b.CreatedAt,
                PromotedAt: b.PromotedAt,
                PromotionEncounterId: b.PromotionEncounterId,
                EnteredByUserId: b.EnteredByUserId,
                EnteredByUserName: b.EnteredByUser?.FullName,
                VerifiedByUserId: b.VerifiedByUserId,
                VerifiedByUserName: b.VerifiedByUser?.FullName,
                ApprovedByUserId: b.ApprovedByUserId,
                ApprovedByUserName: b.ApprovedByUser?.FullName,
                AuditTrail: b.Events
                    .OrderBy(e => e.OccurredAt)
                    .Select(e => new DigitizationEventSummary(
                        e.EventType.ToDbString(),
                        e.OccurredAt,
                        e.ActorUserId,
                        e.Actor?.FullName ?? "Unknown",
                        e.MetadataJson))
                    .ToList()
            );
        }).ToList();

        return new PatientDigitizationHistoryResponse(
            PatientId: patientId,
            TotalBatches: entries.Count,
            PromotedBatches: entries.Count(e => e.Status == "PROMOTED"),
            SupersededBatches: entries.Count(e => e.HasBeenSuperseded),
            PendingBatches: entries.Count(e => e.Status != "PROMOTED" && e.Status != "REJECTED"),
            Entries: entries
        );
    }
}