using System.IO;
using System.Text;
using System.Text.Json;
using SharepointToolbox.Core.Models;
using SharepointToolbox.Infrastructure.Persistence;
using SharepointToolbox.Services;

namespace SharepointToolbox.Tests.Services;

[Trait("Category", "Unit")]
public class SettingsServiceTests : IDisposable
{
    private readonly string _tempFile;

    public SettingsServiceTests()
    {
        _tempFile = Path.GetTempFileName();
        File.Delete(_tempFile);
    }

    public void Dispose()
    {
        if (File.Exists(_tempFile)) File.Delete(_tempFile);
        if (File.Exists(_tempFile + ".tmp")) File.Delete(_tempFile + ".tmp");
    }

    private SettingsRepository CreateRepository() => new(_tempFile);
    private SettingsService CreateService() => new(CreateRepository());

    [Fact]
    public async Task LoadAsync_MissingFile_ReturnsDefaultSettings()
    {
        var repo = CreateRepository();

        var settings = await repo.LoadAsync();

        Assert.Equal(string.Empty, settings.DataFolder);
        Assert.Equal("en", settings.Lang);
    }

    [Fact]
    public async Task SaveAndLoad_RoundTrips_DataFolderAndLang()
    {
        var repo = CreateRepository();
        var original = new AppSettings { DataFolder = @"C:\Exports", Lang = "fr" };

        await repo.SaveAsync(original);
        var loaded = await repo.LoadAsync();

        Assert.Equal(@"C:\Exports", loaded.DataFolder);
        Assert.Equal("fr", loaded.Lang);
    }

    [Fact]
    public async Task SaveAsync_SerializedJson_UsesDataFolderAndLangKeys()
    {
        var repo = CreateRepository();
        await repo.SaveAsync(new AppSettings { DataFolder = @"C:\Exports", Lang = "fr" });

        var json = await File.ReadAllTextAsync(_tempFile);
        using var doc = JsonDocument.Parse(json);

        Assert.True(doc.RootElement.TryGetProperty("dataFolder", out _),
            "JSON must contain 'dataFolder' key (camelCase for schema compatibility)");
        Assert.True(doc.RootElement.TryGetProperty("lang", out _),
            "JSON must contain 'lang' key (camelCase for schema compatibility)");
    }

    [Fact]
    public async Task SaveAsync_UsesTmpFileThenMove()
    {
        var repo = CreateRepository();

        // The .tmp file should not exist after a successful save
        await repo.SaveAsync(new AppSettings { DataFolder = @"C:\Test", Lang = "en" });

        Assert.False(File.Exists(_tempFile + ".tmp"),
            "Temp file should have been moved/deleted after successful save");
        Assert.True(File.Exists(_tempFile), "Settings file must exist after save");
    }

    [Fact]
    public async Task SetLanguageAsync_PersistsLang()
    {
        var service = CreateService();

        await service.SetLanguageAsync("fr");

        var settings = await service.GetSettingsAsync();
        Assert.Equal("fr", settings.Lang);
    }

    [Fact]
    public async Task SetDataFolderAsync_PersistsPath()
    {
        var service = CreateService();

        await service.SetDataFolderAsync(@"C:\Exports");

        var settings = await service.GetSettingsAsync();
        Assert.Equal(@"C:\Exports", settings.DataFolder);
    }

    [Fact]
    public async Task SetDataFolderAsync_EmptyString_IsAllowed()
    {
        var service = CreateService();
        await service.SetDataFolderAsync(@"C:\Exports");

        await service.SetDataFolderAsync(string.Empty);

        var settings = await service.GetSettingsAsync();
        Assert.Equal(string.Empty, settings.DataFolder);
    }

    [Fact]
    public async Task SetLanguageAsync_InvalidCode_ThrowsArgumentException()
    {
        var service = CreateService();

        await Assert.ThrowsAsync<ArgumentException>(() => service.SetLanguageAsync("de"));
    }
}
