using System.IO;
using System.Text;
using System.Text.Json;
using SharepointToolbox.Core.Models;

namespace SharepointToolbox.Infrastructure.Persistence;

public class SettingsRepository
{
    private readonly string _filePath;
    private readonly SemaphoreSlim _writeLock = new(1, 1);

    public SettingsRepository(string filePath)
    {
        _filePath = filePath;
    }

    public async Task<AppSettings> LoadAsync()
    {
        if (!File.Exists(_filePath))
            return new AppSettings();

        string json;
        try
        {
            json = await File.ReadAllTextAsync(_filePath, Encoding.UTF8);
        }
        catch (IOException ex)
        {
            throw new InvalidDataException($"Failed to read settings file: {_filePath}", ex);
        }

        try
        {
            var settings = JsonSerializer.Deserialize<AppSettings>(json,
                new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
            return settings ?? new AppSettings();
        }
        catch (JsonException ex)
        {
            throw new InvalidDataException($"Settings file contains invalid JSON: {_filePath}", ex);
        }
    }

    public async Task SaveAsync(AppSettings settings)
    {
        await _writeLock.WaitAsync();
        try
        {
            var json = JsonSerializer.Serialize(settings,
                new JsonSerializerOptions
                {
                    WriteIndented = true,
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });

            var tmpPath = _filePath + ".tmp";
            var dir = Path.GetDirectoryName(_filePath);
            if (!string.IsNullOrEmpty(dir))
                Directory.CreateDirectory(dir);

            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();
        }
    }
}
