using Api.Database; using Api.Database.Entities; using Api.Extensions; using Api.Mapping; using Api.Services.Interfaces; using Common.Dtos.Common; using Common.Dtos.Season; using Common.Extensions; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Distributed; namespace Api.Services.Implementation; public class SeasonService(SanStudentContext context, IDistributedCache cache) : ISeasonService, IServiceHelper { private readonly SanStudentContext _context = context; private readonly IDistributedCache _cache = cache; private List _cacheKeys = []; public async Task CreateAsync(CreateSeasonRequest request) { try { var problems = await Validate(request); if (problems.Errors.Count > 0) { return new CreateSeasonResponse { Ok = false, CreateSeasonResult = string.Join(", ", problems.Errors) }; } var season = new Season() { Name = request.Name!.Trim(), StartDate = request.StartDate, EndDate = request.EndDate }; _context.Seasons.Add(season); await _context.SaveChangesAsync(); await RemoveCache(); return new CreateSeasonResponse { Ok = true, CreateSeasonResult = $"Zapisano nowy semestr \"{season.Name}\"", }; } catch (Exception error) { return new CreateSeasonResponse { Ok = false, CreateSeasonResult = $"Błąd podczas próby zapisu semestru: {error.Message}", }; } } public async Task GetAllAsync() { var key = "seasons"; AddKeyToCache(key); var cachedSeasons = await _cache.GetStringAsync(key); if (!string.IsNullOrEmpty(cachedSeasons)) return cachedSeasons.FromJson(); var query = _context.Seasons as IQueryable; var result = await query .Where(s => s.EndDate > DateOnly.FromDateTime(DateTime.Now)) .OrderBy(s => s.StartDate) .ThenBy(s => s.Name) .Select(s => s.ToSeasonDto()).ToArrayAsync(); await _cache.SetWithExpirationTimeAsync(key, result, 131487); return result; } public async Task> GetAllPagedAsync(GetSeasonsRequest request) { var key = $"seasons_{request.PageNumber}_{request.PageSize}"; if (!string.IsNullOrWhiteSpace(request.Name)) key += $"_{request.Name.ToLower()}"; if (request.HideObsolete.HasValue && request.HideObsolete.Value) key += $"_{true}"; AddKeyToCache(key); var cachedSeasons = await _cache.GetStringAsync(key); if (!string.IsNullOrEmpty(cachedSeasons)) return cachedSeasons.FromJson>(); var query = _context.Seasons as IQueryable; if (!string.IsNullOrEmpty(request.Name)) query = query.Where(s => s.Name.ToLower().StartsWith(request.Name.ToLower())); if (request.HideObsolete.HasValue && request.HideObsolete.Value) query = query.Where(s => s.EndDate > DateOnly.FromDateTime(DateTime.Now)); var data = query .OrderBy(s => s.StartDate) .ThenBy(s => s.Name) .Select(s => s.ToSeasonDto()); var result = await data.ToPagedListAsync(request.PageNumber, request.PageSize); await _cache.SetWithExpirationTimeAsync(key, result, 131487); return result; } public async Task Validate(CreateSeasonRequest request) { var problems = new ValidationProblems(); if (string.IsNullOrWhiteSpace(request.Name)) problems.Errors.Add("Brak nazwy semestru"); if (problems.Errors.Count > 0) return problems; var season = await _context.Seasons .FirstOrDefaultAsync(s => s.Name.ToLower() == request.Name!.ToLower()); if (season is not null) problems.Errors.Add("Semestr o podanej nazwie już istnieje"); season = await _context.Seasons .FirstOrDefaultAsync(s => s.StartDate == request.StartDate); if (season is not null) problems.Errors.Add("Semestr o podanej dacie rozpoczęcia już istnieje"); season = await _context.Seasons .FirstOrDefaultAsync(s => s.EndDate == request.EndDate); if (season is not null) problems.Errors.Add("Semestr o podanej dacie zakończenia już istnieje"); return problems; } public async Task RemoveCache() { foreach (var cacheKey in _cacheKeys) await _cache.RemoveAsync(cacheKey); } public void AddKeyToCache(string key) { if (!_cacheKeys.Contains(key)) _cacheKeys.Add(key); } }