namespace MBN_STOCK_WEBVIEW.Playout.Tests;

internal sealed class EnvironmentScope : IDisposable
{
    private readonly Dictionary<string, string?> _originalValues = new(StringComparer.Ordinal);

    public EnvironmentScope Set(string name, string? value)
    {
        if (!_originalValues.ContainsKey(name))
        {
            _originalValues.Add(name, Environment.GetEnvironmentVariable(name));
        }

        Environment.SetEnvironmentVariable(name, value);
        return this;
    }

    public void Dispose()
    {
        foreach (var pair in _originalValues)
        {
            Environment.SetEnvironmentVariable(pair.Key, pair.Value);
        }
    }
}

internal sealed class TemporaryJsonFile : IDisposable
{
    private TemporaryJsonFile(string path)
    {
        Path = path;
    }

    public string Path { get; }

    public static TemporaryJsonFile Create(string json)
    {
        var directory = System.IO.Path.Combine(
            System.IO.Path.GetTempPath(),
            "MBN_STOCK_WEBVIEW.Playout.Tests",
            Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(directory);
        var path = System.IO.Path.Combine(directory, "playout.local.json");
        File.WriteAllText(path, json);
        return new TemporaryJsonFile(path);
    }

    public static TemporaryJsonFile Missing()
    {
        var directory = System.IO.Path.Combine(
            System.IO.Path.GetTempPath(),
            "MBN_STOCK_WEBVIEW.Playout.Tests",
            Guid.NewGuid().ToString("N"));
        return new TemporaryJsonFile(
            System.IO.Path.Combine(directory, "missing-playout.local.json"));
    }

    public void Dispose()
    {
        var directory = System.IO.Path.GetDirectoryName(Path);
        if (directory is not null && Directory.Exists(directory))
        {
            Directory.Delete(directory, recursive: true);
        }
    }
}

internal sealed class TemporarySceneDirectory : IDisposable
{
    private TemporarySceneDirectory(string path)
    {
        Path = path;
    }

    public string Path { get; }

    public static TemporarySceneDirectory Create(params string[] relativeFiles)
    {
        var path = System.IO.Path.Combine(
            System.IO.Path.GetTempPath(),
            "MBN_STOCK_WEBVIEW.Playout.Tests",
            Guid.NewGuid().ToString("N"),
            "Scenes");
        Directory.CreateDirectory(path);
        var result = new TemporarySceneDirectory(path);
        foreach (var relativeFile in relativeFiles)
        {
            result.AddFile(relativeFile);
        }

        return result;
    }

    public string AddFile(string relativePath)
    {
        var fullPath = System.IO.Path.GetFullPath(System.IO.Path.Combine(Path, relativePath));
        var rootPrefix = Path.EndsWith(System.IO.Path.DirectorySeparatorChar)
            ? Path
            : Path + System.IO.Path.DirectorySeparatorChar;
        if (!fullPath.StartsWith(rootPrefix, StringComparison.OrdinalIgnoreCase))
        {
            throw new ArgumentException("Test file must remain under the temporary scene directory.", nameof(relativePath));
        }

        Directory.CreateDirectory(System.IO.Path.GetDirectoryName(fullPath)!);
        File.WriteAllText(fullPath, "fake test scene; never loaded by a real COM server");
        return fullPath;
    }

    public void Dispose()
    {
        var parent = Directory.GetParent(Path)?.FullName;
        if (parent is not null && Directory.Exists(parent))
        {
            Directory.Delete(parent, recursive: true);
        }
    }
}
