using System;
using System.IO;
using System.Linq;
using MongoDB.Bson;
using Mongo2Go;
using Xunit;
using MongoDB.Driver;

namespace StellaOps.Feedser.Testing;

public sealed class MongoIntegrationFixture : IAsyncLifetime
{
    public MongoDbRunner Runner { get; private set; } = null!;
    public IMongoDatabase Database { get; private set; } = null!;
    public IMongoClient Client { get; private set; } = null!;

    public Task InitializeAsync()
    {
        EnsureMongo2GoEnvironment();
        Runner = MongoDbRunner.Start(singleNodeReplSet: true);
        Client = new MongoClient(Runner.ConnectionString);
        Database = Client.GetDatabase($"feedser-tests-{Guid.NewGuid():N}");
        return Task.CompletedTask;
    }

    public Task DisposeAsync()
    {
        Runner.Dispose();
        return Task.CompletedTask;
    }

    private static void EnsureMongo2GoEnvironment()
    {
        if (!OperatingSystem.IsLinux())
        {
            return;
        }

        var libraryPath = ResolveOpenSslLibraryPath();
        if (libraryPath is null)
        {
            return;
        }

        var existing = Environment.GetEnvironmentVariable("LD_LIBRARY_PATH");
        if (string.IsNullOrEmpty(existing))
        {
            Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", libraryPath);
            return;
        }

        var segments = existing.Split(':', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (!segments.Contains(libraryPath, StringComparer.Ordinal))
        {
            Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", string.Join(':', new[] { libraryPath }.Concat(segments)));
        }
    }

    private static string? ResolveOpenSslLibraryPath()
    {
        var current = AppContext.BaseDirectory;
        while (!string.IsNullOrEmpty(current))
        {
            var candidate = Path.Combine(current, "tools", "openssl", "linux-x64");
            if (Directory.Exists(candidate))
            {
                return candidate;
            }

            var parent = Directory.GetParent(current);
            if (parent is null)
            {
                break;
            }

            current = parent.FullName;
        }

        return null;
    }
}
