using System.Data;
using MMoneyCoderSharp.Data;

namespace MBN_STOCK_WEBVIEW.Core.Tests;

public sealed class DataQueryExecutorTests : IDisposable
{
    public DataQueryExecutorTests() => DataQueryExecutor.Reset();

    public void Dispose() => DataQueryExecutor.Reset();

    [Fact]
    public void Configure_PublishesExecutorAndResetRemovesIt()
    {
        var executor = new StubExecutor();

        DataQueryExecutor.Configure(executor);

        Assert.True(DataQueryExecutor.IsConfigured);
        Assert.Same(executor, DataQueryExecutor.Current);

        DataQueryExecutor.Reset();

        Assert.False(DataQueryExecutor.IsConfigured);
        Assert.Throws<InvalidOperationException>(() => DataQueryExecutor.Current);
    }

    [Fact]
    public void Configure_RejectsNullWithoutReplacingCurrentExecutor()
    {
        var executor = new StubExecutor();
        DataQueryExecutor.Configure(executor);

        Assert.Throws<ArgumentNullException>(() => DataQueryExecutor.Configure(null!));

        Assert.Same(executor, DataQueryExecutor.Current);
    }

    [Fact]
    public void ConfigureAndReset_AreSafeUnderConcurrentPublication()
    {
        var executors = Enumerable.Range(0, 64).Select(_ => new StubExecutor()).ToArray();

        Parallel.ForEach(executors, executor =>
        {
            DataQueryExecutor.Configure(executor);
            _ = DataQueryExecutor.IsConfigured;
            DataQueryExecutor.Reset();
        });

        DataQueryExecutor.Configure(executors[^1]);
        Assert.Same(executors[^1], DataQueryExecutor.Current);
    }

    private sealed class StubExecutor : IDataQueryExecutor
    {
        public DataTable Execute(DataSourceKind source, string tableName, string query) => new();

        public Task<DataTable> ExecuteAsync(
            DataSourceKind source,
            string tableName,
            string query,
            CancellationToken cancellationToken = default) => Task.FromResult(new DataTable());
    }
}
