using Health.Application.HealthRecords;

namespace Health.Infrastructure.HealthRecords;

public sealed class EfHealthRecordRepository(AppDbContext db) : IHealthRecordRepository
{
    private readonly AppDbContext _db = db;

    public async Task<IReadOnlyList<HealthRecord>> ListAsync(Guid userId, HealthMetricType? type, DateTime? recordedAfter, int limit, CancellationToken ct)
    {
        var query = _db.HealthRecords.Where(r => r.UserId == userId);

        if (type.HasValue)
            query = query.Where(r => r.MetricType == type.Value);

        if (recordedAfter.HasValue)
            query = query.Where(r => r.RecordedAt >= recordedAfter.Value);

        return await query.OrderByDescending(r => r.RecordedAt).Take(limit).ToListAsync(ct);
    }

    public Task<HealthRecord?> GetOwnedAsync(Guid userId, Guid id, CancellationToken ct) =>
        _db.HealthRecords.FirstOrDefaultAsync(r => r.Id == id && r.UserId == userId, ct);

    public Task<HealthRecord?> GetLatestByTypeAsync(Guid userId, HealthMetricType type, CancellationToken ct) =>
        _db.HealthRecords
            .Where(r => r.UserId == userId && r.MetricType == type)
            .OrderByDescending(r => r.RecordedAt)
            .FirstOrDefaultAsync(ct);

    public async Task<IReadOnlyList<HealthRecord>> GetTrendAsync(Guid userId, HealthMetricType type, DateTime recordedAfter, CancellationToken ct) =>
        await _db.HealthRecords
            .Where(r => r.UserId == userId && r.MetricType == type && r.RecordedAt >= recordedAfter)
            .OrderBy(r => r.RecordedAt)
            .ToListAsync(ct);

    public async Task AddAsync(HealthRecord record, CancellationToken ct) =>
        await _db.HealthRecords.AddAsync(record, ct);

    public void Delete(HealthRecord record) =>
        _db.HealthRecords.Remove(record);

    public Task SaveChangesAsync(CancellationToken ct) =>
        _db.SaveChangesAsync(ct);
}
