using Microsoft.EntityFrameworkCore;

public class LocalAlertService : ILocalAlertService
{
    private readonly GatewayDbContext _db;

    public LocalAlertService(GatewayDbContext db) => _db = db;

    public async Task<LocalClinicalAlert> AcknowledgeAsync(
        Guid id, AcknowledgeAlertRequest req, string clinicianId)
    {
        var alert = await _db.ClinicalAlerts.FindAsync(id)
            ?? throw new NotFoundException("Alert not found.", "ALERT_NOT_FOUND");

        if (alert.Status is not (AlertStatus.Open or AlertStatus.Escalated))
            throw new ConflictException("Alert cannot be acknowledged.", "ALERT_NOT_ACKNOWLEDGEABLE");

        alert.Status = AlertStatus.Acknowledged;
        alert.AcknowledgedAt = DateTimeOffset.UtcNow;
        alert.AcknowledgedBy = clinicianId;

        BufferedSyncWriter.Enqueue(_db, BufferedSyncItemType.Ack, new
        {
            clientRef = Guid.NewGuid(),
            alert.ClientAlertId,
            clinicianId,
            acknowledgedAt = alert.AcknowledgedAt,
            req.Note
        }, $"ack:{alert.ClientAlertId}:{alert.AcknowledgedAt:o}", alert.EncounterId, alert.AcknowledgedAt!.Value);

        await _db.SaveChangesAsync();
        return alert;
    }

    public async Task<LocalClinicalAlert> ResolveAsync(Guid id)
    {
        var alert = await _db.ClinicalAlerts.FindAsync(id)
            ?? throw new NotFoundException("Alert not found.", "ALERT_NOT_FOUND");

        if (alert.Status != AlertStatus.Acknowledged)
            throw new ConflictException("Alert must be acknowledged first.", "ALERT_NOT_ACKNOWLEDGED");

        alert.Status = AlertStatus.Resolved;
        alert.ResolvedAt = DateTimeOffset.UtcNow;

        BufferedSyncWriter.Enqueue(_db, BufferedSyncItemType.Resolve, new
        {
            clientRef = Guid.NewGuid(),
            alert.ClientAlertId,
            clinicianId = alert.AcknowledgedBy,
            resolvedAt = alert.ResolvedAt,
            note = (string?)null
        }, $"resolve:{alert.ClientAlertId}", alert.EncounterId, alert.ResolvedAt!.Value);

        await _db.SaveChangesAsync();
        return alert;
    }

    public async Task<PagedResult<LocalClinicalAlert>> ListAsync(
        Guid? encounterId, string? status, int page, int pageSize)
    {
        page = Math.Max(1, page);
        pageSize = Math.Clamp(pageSize, 1, 100);

        var q = _db.ClinicalAlerts.AsNoTracking().AsQueryable();
        if (encounterId.HasValue) q = q.Where(a => a.EncounterId == encounterId);
        if (!string.IsNullOrEmpty(status))
        {
            var parsedStatus = AlertStatusExtensions.FromDbString(status);
            q = q.Where(a => a.Status == parsedStatus);
        }
        var total = await q.CountAsync();
        var items = await q.OrderByDescending(a => a.TriggeredAt)
            .Skip((page - 1) * pageSize).Take(pageSize).ToListAsync();
        return new PagedResult<LocalClinicalAlert>(items, page, pageSize, total);
    }
}