using System.Reflection;
using QuantEngine.Infrastructure.External;

namespace QuantEngine.Core.Tests;

public class SecurityTests
{
    [Theory]
    [InlineData("/uapi/domestic-stock/v1/quotations/inquire-price", "FHKST01010100")]
    [InlineData("/uapi/domestic-stock/v1/quotations/inquire-investor", "FHKST01010900")]
    [InlineData("/uapi/domestic-stock/v1/quotations/inquire-daily-itemchartprice", "FHKST03010100")]
    public void AssertReadOnly_AllowsReadOnlyQuotationPaths(string path, string trId)
    {
        var client = CreateClient();

        var ex = Record.Exception(() => InvokeAssertReadOnly(client, path, trId));

        Assert.Null(ex);
    }

    [Theory]
    [InlineData("/uapi/domestic-stock/v1/trading/order-cash", "VTTC0802U")]
    [InlineData("/uapi/domestic-stock/v1/quotations/inquire-price", "TTTC084000")]
    [InlineData("/uapi/domestic-stock/v1/trading/order-cash", "FHKST01010100")]
    public void AssertReadOnly_BlocksTradingPathsOrIds(string path, string trId)
    {
        var client = CreateClient();

        var ex = Assert.Throws<TargetInvocationException>(() => InvokeAssertReadOnly(client, path, trId));
        Assert.IsType<InvalidOperationException>(ex.InnerException);
        Assert.Contains("BLOCKED", ex.InnerException!.Message);
    }

    [Fact]
    public void AssertReadOnly_BlocksKnownTradingTrIdPrefixes()
    {
        var client = CreateClient();

        var ex = Assert.Throws<TargetInvocationException>(() => InvokeAssertReadOnly(client, "/uapi/domestic-stock/v1/quotations/inquire-price", "VTTC8434R00"));
        Assert.IsType<InvalidOperationException>(ex.InnerException);
        Assert.Contains("TR_ID", ex.InnerException!.Message);
    }

    private static KisApiClient CreateClient()
    {
        Environment.SetEnvironmentVariable("KIS_APP_Key_TEST", "mock-key");
        Environment.SetEnvironmentVariable("KIS_APP_Secret_TEST", "mock-secret");
        return new KisApiClient(new HttpClient(new DummyHandler()), new NoopConnectionFactory());
    }

    private static void InvokeAssertReadOnly(KisApiClient client, string path, string trId)
    {
        var method = typeof(KisApiClient).GetMethod("AssertReadOnly", BindingFlags.Instance | BindingFlags.NonPublic)
            ?? throw new InvalidOperationException("AssertReadOnly method not found.");
        method.Invoke(client, new object[] { path, trId });
    }

    private sealed class DummyHandler : HttpMessageHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
            => Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.OK));
    }

    private sealed class NoopConnectionFactory : QuantEngine.Infrastructure.Data.IDbConnectionFactory
    {
        public System.Data.IDbConnection CreateConnection() => throw new NotSupportedException("Not needed for read-only guard tests.");
    }
}
