using AutoMapper; using LANCommander.Server.Data; using LANCommander.Server.Data.Models; using LANCommander.Helpers; using LANCommander.SDK.Enums; using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; using ZiggyCreatures.Caching.Fusion; using LANCommander.SDK; namespace LANCommander.Server.Services { public sealed class GameSaveService( ILogger logger, SettingsProvider settingsProvider, IFusionCache cache, IMapper mapper, IHttpContextAccessor httpContextAccessor, IDbContextFactory contextFactory, StorageLocationService storageLocationService) : BaseDatabaseService(logger, settingsProvider, cache, mapper, httpContextAccessor, contextFactory) { public override async Task AddAsync(GameSave entity) { return await base.AddAsync(entity, async context => { await context.UpdateRelationshipAsync(gs => gs.Game); await context.UpdateRelationshipAsync(gs => gs.StorageLocation); await context.UpdateRelationshipAsync(gs => gs.User); }); } public override async Task UpdateAsync(GameSave entity) { return await base.UpdateAsync(entity, async context => { await context.UpdateRelationshipAsync(gs => gs.Game); await context.UpdateRelationshipAsync(gs => gs.StorageLocation); await context.UpdateRelationshipAsync(gs => gs.User); }); } public override async Task DeleteAsync(GameSave entity) { FileHelpers.DeleteIfExists(await GetSavePathAsync(entity.Id)); await base.DeleteAsync(entity); } public async Task GetSavePathAsync(Guid gameId, Guid userId) { var save = await SortBy(gs => gs.CreatedOn, Data.Enums.SortDirection.Descending).FirstOrDefaultAsync(gs => gs.GameId == gameId && gs.UserId == userId); if (save == null) return null; return GetSavePath(save); } public async Task GetSavePathAsync(Guid id) { // Use get with predicate to avoid async var save = await FirstOrDefaultAsync(gs => gs.Id == id); if (save == null) return null; return GetSavePath(save); } public string GetSavePath(GameSave save) { var gameId = save.GameId ?? throw new InvalidOperationException($"No game ID is available for save {save.Id}"); return AppPaths.ResolveStorageLocationPath(save.StorageLocation.Path, save.UserId.ToString(), gameId.ToString(), save.Id.ToString()); } public async Task GetDefaultStorageLocationAsync() { return await storageLocationService.FirstOrDefaultAsync(l => l.Type == StorageLocationType.Save && l.Default); } } }