using System.Data;
using MBN_STOCK_WEBVIEW.Core.Playout.Scenes;
using MMoneyCoderSharp.Data;

namespace MBN_STOCK_WEBVIEW.Core.Tests;

public sealed class PanelSceneDataLoadersTests
{
    [Fact]
    public async Task NxtLoader_UsesMariaParameterAndMapsS5006Dto()
    {
        var table = new DataTable();
        foreach (var column in new[]
        {
            "STOCK_NAME", "CURR_PRICE", "CHG_TYPE", "NET_CHG", "RATE",
            "INIT_PRICE", "INIT_RATE", "HIGH_PRICE", "HIGH_RATE", "LOW_PRICE", "LOW_RATE"
        })
        {
            table.Columns.Add(column, typeof(object));
        }
        table.Rows.Add("A사", 1000m, "상승", 50m, 5.26m, 960m, 1m, 1100m, 10m, 900m, -10m);
        var executor = new RecordingExecutor(table);

        var data = await new S5006NxtSceneDataLoader(executor).LoadAsync(
            LegacyDomesticEquityMarket.NxtKospi,
            "005930");
        var mutations = new S5006SceneMutationBuilder().Build(data);

        Assert.Equal(DataSourceKind.MariaDb, executor.Source);
        Assert.NotNull(executor.Spec);
        Assert.Contains("@stockCode", executor.Spec.Sql, StringComparison.Ordinal);
        var parameter = Assert.Single(executor.Spec.Parameters);
        Assert.Equal("stockCode", parameter.Name);
        Assert.Equal("005930", parameter.Value);
        Assert.Equal(DbType.String, parameter.DbType);
        Assert.Equal(ScenePriceDirection.Up, data.Direction);
        Assert.Equal(1000, data.CurrentPrice);
        Assert.NotEmpty(mutations);
        Assert.Equal(0, executor.StringCalls);
    }

    [Theory]
    [InlineData(LegacyDomesticEquityMarket.Kospi)]
    [InlineData(LegacyDomesticEquityMarket.Kosdaq)]
    public async Task NxtLoader_RejectsNonNxtMarketsBeforeQuery(LegacyDomesticEquityMarket market)
    {
        var executor = new RecordingExecutor(new DataTable());

        await Assert.ThrowsAsync<LegacySceneDataException>(() =>
            new S5006NxtSceneDataLoader(executor).LoadAsync(market, "005930"));

        Assert.Null(executor.Spec);
    }

    private sealed class RecordingExecutor(DataTable table) : IDataQueryExecutor
    {
        public DataSourceKind Source { get; private set; }

        public DataQuerySpec? Spec { get; private set; }

        public int StringCalls { get; private set; }

        public DataTable Execute(DataSourceKind source, string tableName, string query)
        {
            StringCalls++;
            throw new InvalidOperationException();
        }

        public Task<DataTable> ExecuteAsync(
            DataSourceKind source,
            string tableName,
            string query,
            CancellationToken cancellationToken = default)
        {
            StringCalls++;
            throw new InvalidOperationException();
        }

        public Task<DataTable> ExecuteAsync(
            DataSourceKind source,
            string tableName,
            DataQuerySpec query,
            CancellationToken cancellationToken = default)
        {
            Source = source;
            Spec = query;
            return Task.FromResult(table.Copy());
        }
    }
}
