using System.IO; using System.Text; using System.Text.Json; using SharepointToolbox.Core.Models; namespace SharepointToolbox.Infrastructure.Persistence; public class TemplateRepository { private readonly string _directoryPath; private readonly SemaphoreSlim _writeLock = new(1, 1); private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase, PropertyNameCaseInsensitive = true, }; public TemplateRepository(string directoryPath) { _directoryPath = directoryPath; } public async Task> GetAllAsync() { if (!Directory.Exists(_directoryPath)) return new List(); var templates = new List(); foreach (var file in Directory.GetFiles(_directoryPath, "*.json")) { try { var json = await File.ReadAllTextAsync(file, Encoding.UTF8); var template = JsonSerializer.Deserialize(json, JsonOptions); if (template != null) templates.Add(template); } catch (JsonException) { // Skip corrupted template files } } return templates.OrderByDescending(t => t.CapturedAt).ToList(); } public async Task GetByIdAsync(string id) { var filePath = GetFilePath(id); if (!File.Exists(filePath)) return null; var json = await File.ReadAllTextAsync(filePath, Encoding.UTF8); return JsonSerializer.Deserialize(json, JsonOptions); } public async Task SaveAsync(SiteTemplate template) { await _writeLock.WaitAsync(); try { if (!Directory.Exists(_directoryPath)) Directory.CreateDirectory(_directoryPath); var json = JsonSerializer.Serialize(template, JsonOptions); var filePath = GetFilePath(template.Id); var tmpPath = filePath + ".tmp"; await File.WriteAllTextAsync(tmpPath, json, Encoding.UTF8); // Validate round-trip before replacing JsonDocument.Parse(await File.ReadAllTextAsync(tmpPath, Encoding.UTF8)).Dispose(); File.Move(tmpPath, filePath, overwrite: true); } finally { _writeLock.Release(); } } public Task DeleteAsync(string id) { var filePath = GetFilePath(id); if (File.Exists(filePath)) File.Delete(filePath); return Task.CompletedTask; } public async Task RenameAsync(string id, string newName) { var template = await GetByIdAsync(id); if (template == null) throw new InvalidOperationException($"Template not found: {id}"); template.Name = newName; await SaveAsync(template); } private string GetFilePath(string id) => Path.Combine(_directoryPath, $"{id}.json"); }