using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using UniVerse.Application.DTOs.Sync; using UniVerse.Application.Interfaces; using UniVerse.Domain.Entities; using UniVerse.Infrastructure.Data; namespace UniVerse.Infrastructure.Services; public class ScheduleSyncService : IScheduleSyncService { private readonly AppDbContext _db; private readonly IModeusApiClient _modeus; private readonly ILogger _logger; private static SyncStatusDto _lastStatus = new(null, "idle", null); public ScheduleSyncService(AppDbContext db, IModeusApiClient modeus, ILogger logger) { _db = db; _modeus = modeus; _logger = logger; } public async Task SyncScheduleAsync(SyncScheduleRequest request) { int created = 0, updated = 0, skipped = 0; try { var events = await _modeus.SearchEventsAsync(request); foreach (var ev in events.Events) { var existing = await _db.Lectures.FirstOrDefaultAsync(l => l.ExternalId == ev.Id); if (existing != null) { updated++; existing.StartsAt = ev.StartsAt; existing.EndsAt = ev.EndsAt; existing.UpdatedAt = DateTime.UtcNow; } else { var course = await _db.Courses.FirstOrDefaultAsync(c => c.ExternalId == ev.TypeId); if (course == null) { course = new Course { Name = ev.Name, ExternalId = ev.TypeId, IsSynced = true }; _db.Courses.Add(course); await _db.SaveChangesAsync(); } _db.Lectures.Add(new Lecture { CourseId = course.Id, Title = ev.Name, ExternalId = ev.Id, StartsAt = ev.StartsAt, EndsAt = ev.EndsAt }); created++; } } await _db.SaveChangesAsync(); var result = new SyncResultDto(created, updated, skipped, null); _lastStatus = new SyncStatusDto(DateTime.UtcNow, "completed", result); return result; } catch (Exception ex) { _logger.LogError(ex, "Schedule sync failed"); var result = new SyncResultDto(created, updated, skipped, ex.Message); _lastStatus = new SyncStatusDto(DateTime.UtcNow, "failed", result); return result; } } public async Task SyncRoomsAsync() { int created = 0, updated = 0, skipped = 0; try { var rooms = await _modeus.SearchRoomsAsync(); foreach (var room in rooms?.RoomItems ?? []) { if (room is null || string.IsNullOrWhiteSpace(room.Id) || string.IsNullOrWhiteSpace(room.Name)) { skipped++; continue; } var existing = await _db.Locations.FirstOrDefaultAsync(l => l.ExternalId == room.Id); if (existing != null) { existing.Name = room.Name; existing.Room = room.NameShort; existing.Building = room.Building?.Name ?? room.Building?.NameShort; existing.Address = room.Building?.Address; updated++; } else { _db.Locations.Add(new Location { Name = room.Name, Room = room.NameShort, Building = room.Building?.Name ?? room.Building?.NameShort, Address = room.Building?.Address, ExternalId = room.Id }); created++; } } await _db.SaveChangesAsync(); var result = new SyncResultDto(created, updated, skipped, null); _lastStatus = new SyncStatusDto(DateTime.UtcNow, "completed", result); return result; } catch (Exception ex) { _logger.LogError(ex, "Rooms sync failed"); var result = new SyncResultDto(created, updated, skipped, ex.Message); _lastStatus = new SyncStatusDto(DateTime.UtcNow, "failed", result); return result; } } public async Task> SearchEmployeesAsync(string fullname) { var employees = await _modeus.SearchEmployeeAsync(fullname); return employees.Select(e => new EmployeeDto(e.Id, e.FullName, e.Department)).ToList(); } public Task GetLastSyncStatusAsync() => Task.FromResult(_lastStatus); }