using System.Text;
using Metin2Launcher.Apply;
using Xunit;

namespace Metin2Launcher.Tests;

public class AtomicApplierTests : IDisposable
{
    private readonly string _root;

    public AtomicApplierTests()
    {
        _root = Path.Combine(Path.GetTempPath(), "metin-apply-" + Guid.NewGuid());
        Directory.CreateDirectory(_root);
    }

    public void Dispose()
    {
        try { Directory.Delete(_root, recursive: true); } catch { }
    }

    [Fact]
    public void ApplyOne_replaces_existing_target()
    {
        var staging = Path.Combine(_root, "staging", "a.txt");
        var final   = Path.Combine(_root, "client",  "a.txt");
        Directory.CreateDirectory(Path.GetDirectoryName(staging)!);
        Directory.CreateDirectory(Path.GetDirectoryName(final)!);
        File.WriteAllText(final,   "old");
        File.WriteAllText(staging, "new");

        AtomicApplier.ApplyOne(staging, final);

        Assert.Equal("new", File.ReadAllText(final));
        Assert.False(File.Exists(staging));
    }

    [Fact]
    public void ApplyOne_creates_missing_directory()
    {
        var staging = Path.Combine(_root, "staging", "deep", "b.bin");
        var final   = Path.Combine(_root, "client",  "nested", "newly", "made", "b.bin");
        Directory.CreateDirectory(Path.GetDirectoryName(staging)!);
        File.WriteAllBytes(staging, new byte[] { 1, 2, 3 });

        AtomicApplier.ApplyOne(staging, final);

        Assert.True(File.Exists(final));
        Assert.Equal(new byte[] { 1, 2, 3 }, File.ReadAllBytes(final));
    }

    [Fact]
    public void Apply_moves_all_files_in_order()
    {
        var items = new List<AtomicApplier.StagedFile>();
        for (int i = 0; i < 5; i++)
        {
            var s = Path.Combine(_root, "staging", $"f{i}.txt");
            var f = Path.Combine(_root, "client",  $"f{i}.txt");
            Directory.CreateDirectory(Path.GetDirectoryName(s)!);
            File.WriteAllText(s, $"content-{i}");
            items.Add(new AtomicApplier.StagedFile(s, f));
        }

        AtomicApplier.Apply(items);

        for (int i = 0; i < 5; i++)
        {
            Assert.Equal($"content-{i}", File.ReadAllText(items[i].FinalPath));
        }
    }

    [Fact]
    public void ApplyOne_throws_if_staging_missing()
    {
        var staging = Path.Combine(_root, "staging", "missing.txt");
        var final   = Path.Combine(_root, "client",  "missing.txt");
        Assert.Throws<FileNotFoundException>(() => AtomicApplier.ApplyOne(staging, final));
    }
}
