using System.Net.Http.Json;
using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using UtopiaCanteenSystem.Data;
using UtopiaCanteenSystem.Models;
using System.Net.Http;
namespace UtopiaCanteenSystem.Services;
///
/// Scheduled sync: fetches unsynced ScanRecords, POSTs them to the configured API,
/// and deletes uploaded records from local SQLite on success.
///
public class SyncService : ISyncService
{
private readonly IDbContextFactory _dbFactory;
private readonly IConfigService _configService;
private static readonly HttpClient HttpClient = new();
public SyncService(IDbContextFactory dbFactory, IConfigService configService)
{
_dbFactory = dbFactory;
_configService = configService;
}
public async Task SyncNowAsync(CancellationToken cancellationToken = default)
{
var endpoint = _configService.GetSyncApiEndpoint();
if (string.IsNullOrWhiteSpace(endpoint))
return;
List toSync;
using (var db = _dbFactory.CreateDbContext())
{
toSync = await db.ScanRecords
.Where(r => !r.IsSynced)
.OrderBy(r => r.ScanTime)
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
}
if (toSync.Count == 0)
return;
var payload = toSync.Select(r => new
{
DeviceLocalRowId = r.Id,
ScanTimeUtc = r.ScanTime,
SiteId = r.SiteId ?? string.Empty,
DeviceId = r.DeviceId ?? string.Empty,
r.CardId
}).ToList();
try
{
var response = await HttpClient
.PostAsJsonAsync(endpoint, payload, cancellationToken: cancellationToken)
.ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
return;
var ids = toSync.Select(r => r.Id).ToList();
using (var db = _dbFactory.CreateDbContext())
{
var records = await db.ScanRecords
.Where(r => ids.Contains(r.Id))
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
// On successful upload, delete uploaded scan records from local SQLite.
db.ScanRecords.RemoveRange(records);
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
}
}
catch
{
// Leave records intact; will retry on next run
}
}
}