// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#nullable enable

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Apache.Arrow.Flight.Server;
using Apache.Arrow.Types;
using Arrow.Flight.Protocol.Sql;
using Google.Protobuf;
using Grpc.Core;
using Xunit;

namespace Apache.Arrow.Flight.Sql.Tests;

public class FlightSqlServerTests
{
    [Theory]
    [InlineData(FlightDescriptorType.Path, null)]
    [InlineData(FlightDescriptorType.Command, null)]
    [InlineData(FlightDescriptorType.Command, typeof(CommandGetCatalogs))]
    public void EnsureGetCommandReturnsTheCorrectResponse(FlightDescriptorType type, Type? expectedResult)
    {
        //Given
        FlightDescriptor descriptor;
        if (type == FlightDescriptorType.Command)
        {
            descriptor = expectedResult != null ?
                FlightDescriptor.CreateCommandDescriptor(((IMessage)Activator.CreateInstance(expectedResult!)!).PackAndSerialize().ToByteArray()) :
                FlightDescriptor.CreateCommandDescriptor(ByteString.Empty.ToStringUtf8());
        }
        else
        {
            descriptor = FlightDescriptor.CreatePathDescriptor(System.Array.Empty<string>());
        }

        //When
        var result = FlightSqlServer.GetCommand(descriptor);

        //Then
        Assert.Equal(expectedResult, result?.GetType());
    }

    [Fact]
    public async Task EnsureTheCorrectActionsAreGiven()
    {
        //Given
        var producer = new TestFlightSqlSever();
        var streamWriter = new MockServerStreamWriter<FlightActionType>();

        //When
        await producer.ListActions(streamWriter, new MockServerCallContext());
        var actions = streamWriter.Messages.ToArray();

        Assert.Equal(FlightSqlUtils.FlightSqlActions, actions);
    }

    [Theory]
    [InlineData(false,
        new[] { "catalog_name", "db_schema_name", "table_name", "table_type" },
        new[] { typeof(StringType), typeof(StringType), typeof(StringType), typeof(StringType) },
        new[] { true, true, false, false })
    ]
    [InlineData(true,
        new[] { "catalog_name", "db_schema_name", "table_name", "table_type", "table_schema" },
        new[] { typeof(StringType), typeof(StringType), typeof(StringType), typeof(StringType), typeof(BinaryType) },
        new[] { true, true, false, false, false })
    ]
    public void EnsureTableSchemaIsCorrectWithoutTableSchema(bool includeTableSchemaField, string[] expectedNames, Type[] expectedTypes, bool[] expectedIsNullable)
    {
        // Arrange

        // Act
        var schema = FlightSqlServer.GetTableSchema(includeTableSchemaField);
        var fields = schema.FieldsList;

        //Assert
        Assert.False(schema.HasMetadata);
        Assert.Equal(expectedNames.Length, fields.Count);
        for (int i = 0; i < fields.Count; i++)
        {
            Assert.Equal(expectedNames[i], fields[i].Name);
            Assert.Equal(expectedTypes[i], fields[i].DataType.GetType());
            Assert.Equal(expectedIsNullable[i], fields[i].IsNullable);
        }
    }

    #region FlightInfoTests
    [Theory]
    [InlineData(typeof(CommandStatementQuery), "GetStatementQueryFlightInfo")]
    [InlineData(typeof(CommandPreparedStatementQuery), "GetPreparedStatementQueryFlightInfo")]
    [InlineData(typeof(CommandGetCatalogs), "GetCatalogFlightInfo")]
    [InlineData(typeof(CommandGetDbSchemas), "GetDbSchemaFlightInfo")]
    [InlineData(typeof(CommandGetTables), "GetTablesFlightInfo")]
    [InlineData(typeof(CommandGetTableTypes), "GetTableTypesFlightInfo")]
    [InlineData(typeof(CommandGetSqlInfo), "GetSqlFlightInfo")]
    [InlineData(typeof(CommandGetPrimaryKeys), "GetPrimaryKeysFlightInfo")]
    [InlineData(typeof(CommandGetExportedKeys), "GetExportedKeysFlightInfo")]
    [InlineData(typeof(CommandGetImportedKeys), "GetImportedKeysFlightInfo")]
    [InlineData(typeof(CommandGetCrossReference), "GetCrossReferenceFlightInfo")]
    [InlineData(typeof(CommandGetXdbcTypeInfo), "GetXdbcTypeFlightInfo")]
    public async Task EnsureGetFlightInfoIsCorrectlyRoutedForCommand(Type commandType, string expectedResult)
    {
        //Given
        var command = (IMessage)Activator.CreateInstance(commandType)!;
        var producer = new TestFlightSqlSever();
        var descriptor = FlightDescriptor.CreateCommandDescriptor(command.PackAndSerialize().ToArray());

        //When
        var flightInfo = await producer.GetFlightInfo(descriptor, new MockServerCallContext());

        //Then
        Assert.Equal(expectedResult, flightInfo.Descriptor.Paths.First());
    }


    [Fact]
    public async Task EnsureAnInvalidOperationExceptionIsThrownWhenACommandIsNotSupportedAndHasNoDescriptor()
    {
        //Given
        var producer = new TestFlightSqlSever();

        //When
        async Task<FlightInfo> Act() => await producer.GetFlightInfo(FlightDescriptor.CreatePathDescriptor(""), new MockServerCallContext());
        var exception = await Record.ExceptionAsync(Act);

        //Then
        Assert.Equal("command type  not supported", exception?.Message);
    }

    [Fact]
    public async Task EnsureAnInvalidOperationExceptionIsThrownWhenACommandIsNotSupported()
    {
        //Given
        var producer = new TestFlightSqlSever();
        var command = new CommandPreparedStatementUpdate();
        var descriptor = FlightDescriptor.CreateCommandDescriptor(command.PackAndSerialize().ToArray());

        //When
        async Task<FlightInfo> Act() => await producer.GetFlightInfo(descriptor, new MockServerCallContext());
        var exception = await Record.ExceptionAsync(Act);

        //Then
        Assert.Equal("command type CommandPreparedStatementUpdate not supported", exception?.Message);
    }
    #endregion

    #region DoGetTests

    [Theory]
    [InlineData(typeof(CommandPreparedStatementQuery), "DoGetPreparedStatementQuery")]
    [InlineData(typeof(CommandGetSqlInfo), "DoGetSqlInfo")]
    [InlineData(typeof(CommandGetCatalogs), "DoGetCatalog")]
    [InlineData(typeof(CommandGetTableTypes), "DoGetTableType")]
    [InlineData(typeof(CommandGetTables), "DoGetTables")]
    [InlineData(typeof(CommandGetDbSchemas), "DoGetDbSchema")]
    [InlineData(typeof(CommandGetPrimaryKeys), "DoGetPrimaryKeys")]
    [InlineData(typeof(CommandGetExportedKeys), "DoGetExportedKeys")]
    [InlineData(typeof(CommandGetImportedKeys), "DoGetImportedKeys")]
    [InlineData(typeof(CommandGetCrossReference), "DoGetCrossReference")]
    [InlineData(typeof(CommandGetXdbcTypeInfo), "DoGetXbdcTypeInfo")]
    public async Task EnsureDoGetIsCorrectlyRoutedForADoGetCommand(Type commandType, string expectedResult)
    {
        //Given
        var producer = new TestFlightSqlSever();
        var command = (IMessage)Activator.CreateInstance(commandType)!;
        var ticket = new FlightTicket(command.PackAndSerialize());
        var streamWriter = new MockServerStreamWriter<FlightData>();

        //When
        await producer.DoGet(ticket, new FlightServerRecordBatchStreamWriter(streamWriter), new MockServerCallContext());
        var schema = await streamWriter.Messages.GetSchema();

        //Then
        Assert.Equal(expectedResult, schema.FieldsList[0].Name);
    }

    [Fact]
    public async Task EnsureAnInvalidOperationExceptionIsThrownWhenADoGetCommandIsNotSupported()
    {
        //Given
        var producer = new TestFlightSqlSever();
        var ticket = new FlightTicket("");
        var streamWriter = new MockServerStreamWriter<FlightData>();

        //When
        async Task Act() => await producer.DoGet(ticket, new FlightServerRecordBatchStreamWriter(streamWriter), new MockServerCallContext());
        var exception = await Record.ExceptionAsync(Act);

        //Then
        Assert.Equal("Status(StatusCode=\"InvalidArgument\", Detail=\"DoGet command  is not supported.\")", exception?.Message);
    }
    #endregion

    #region DoActionTests
    [Theory]
    [InlineData(SqlAction.CloseRequest, typeof(ActionClosePreparedStatementRequest), "ClosePreparedStatement")]
    [InlineData(SqlAction.CreateRequest, typeof(ActionCreatePreparedStatementRequest), "CreatePreparedStatement")]
    [InlineData("BadCommand", typeof(ActionCreatePreparedStatementRequest), "Action type BadCommand not supported", true)]
    public async Task EnsureDoActionIsCorrectlyRoutedForAnActionRequest(string actionType, Type actionBodyType, string expectedResponse, bool isException = false)
    {
        //Given
        var producer = new TestFlightSqlSever();
        var actionBody = (IMessage)Activator.CreateInstance(actionBodyType)!;
        var action = new FlightAction(actionType, actionBody.PackAndSerialize());
        var mockStreamWriter = new MockStreamWriter<FlightResult>();

        //When
        async Task Act() => await producer.DoAction(action, mockStreamWriter, new MockServerCallContext());
        var exception = await Record.ExceptionAsync(Act);
        string? actualMessage = isException ? exception?.Message : mockStreamWriter.Messages[0].Body.ToStringUtf8();

        //Then
        Assert.Equal(expectedResponse, actualMessage);
    }
    #endregion

    #region DoPutTests
    [Theory]
    [InlineData(typeof(CommandStatementUpdate), "PutStatementUpdate")]
    [InlineData(typeof(CommandPreparedStatementQuery), "PutPreparedStatementQuery")]
    [InlineData(typeof(CommandPreparedStatementUpdate), "PutPreparedStatementUpdate")]
    [InlineData(typeof(CommandGetXdbcTypeInfo), "Command CommandGetXdbcTypeInfo not supported", true)]
    public async Task EnsureDoPutIsCorrectlyRoutedForTheCommand(Type commandType, string expectedResponse, bool isException = false)
    {
        //Given
        var command = (IMessage)Activator.CreateInstance(commandType)!;
        var producer = new TestFlightSqlSever();
        var descriptor = FlightDescriptor.CreateCommandDescriptor(command.PackAndSerialize().ToArray());
        var recordBatch = new RecordBatch(new Schema(new List<Field>(), null), System.Array.Empty<Int8Array>(), 0);
        var reader = new MockStreamReader<FlightData>(await recordBatch.ToFlightData(descriptor));
        var batchReader = new FlightServerRecordBatchStreamReader(reader);
        var mockStreamWriter = new MockServerStreamWriter<FlightPutResult>();

        //When
        async Task Act() => await producer.DoPut(batchReader, mockStreamWriter, new MockServerCallContext());
        var exception = await Record.ExceptionAsync(Act);
        string? actualMessage = isException ? exception?.Message : mockStreamWriter.Messages[0].ApplicationMetadata.ToStringUtf8();

        //Then
        Assert.Equal(expectedResponse, actualMessage);
    }
    #endregion

    private class MockServerCallContext : ServerCallContext
    {
        protected override Task WriteResponseHeadersAsyncCore(Metadata responseHeaders) => throw new NotImplementedException();

        protected override ContextPropagationToken CreatePropagationTokenCore(ContextPropagationOptions? options) => throw new NotImplementedException();
        protected override string MethodCore => "";
        protected override string HostCore => "";
        protected override string PeerCore => "";
        protected override DateTime DeadlineCore => new();
        protected override Metadata RequestHeadersCore => new();
        protected override CancellationToken CancellationTokenCore => default;
        protected override Metadata ResponseTrailersCore => new();
        protected override Status StatusCore { get; set; }
        protected override WriteOptions? WriteOptionsCore { get; set; } = WriteOptions.Default;
        protected override AuthContext AuthContextCore => new("", new Dictionary<string, List<AuthProperty>>());
    }
}

internal class MockStreamWriter<T> : IServerStreamWriter<T>
{
    public Task WriteAsync(T message)
    {
        _messages.Add(message);
        return Task.FromResult(message);
    }

    public IReadOnlyList<T> Messages => new ReadOnlyCollection<T>(_messages);
    public WriteOptions? WriteOptions { get; set; }
    private readonly List<T> _messages = new();
}

internal class MockServerStreamWriter<T> : IServerStreamWriter<T>
{
    public Task WriteAsync(T message)
    {
        _messages.Add(message);
        return Task.FromResult(message);
    }

    public IReadOnlyList<T> Messages => new ReadOnlyCollection<T>(_messages);
    public WriteOptions? WriteOptions { get; set; }
    private readonly List<T> _messages = new();
}

internal static class MockStreamReaderWriterExtensions
{
    public static async Task<List<RecordBatch>> GetRecordBatches(this IReadOnlyList<FlightData> flightDataList)
    {
        var list = new List<RecordBatch>();
        var recordBatchReader = new FlightServerRecordBatchStreamReader(new MockStreamReader<FlightData>(flightDataList));
        while (await recordBatchReader.MoveNext().ConfigureAwait(false))
        {
            list.Add(recordBatchReader.Current);
        }

        return list;
    }

    public static async Task<Schema> GetSchema(this IEnumerable<FlightData> flightDataList)
    {
        var recordBatchReader = new FlightServerRecordBatchStreamReader(new MockStreamReader<FlightData>(flightDataList));
        return await recordBatchReader.Schema;
    }

    public static async Task<IEnumerable<FlightData>> ToFlightData(this RecordBatch recordBatch, FlightDescriptor? descriptor = null)
    {
        var responseStream = new MockFlightServerRecordBatchStreamWriter();
        await responseStream.WriteRecordBatchAsync(recordBatch);
        if (descriptor == null)
        {
            return responseStream.FlightData;
        }

        return responseStream.FlightData.Select(
            flightData => new FlightData(descriptor, flightData.DataBody, flightData.DataHeader, flightData.AppMetadata)
            );
    }
}

internal class MockStreamReader<T> : IAsyncStreamReader<T>
{
    private readonly IEnumerator<T> _flightActions;

    public MockStreamReader(IEnumerable<T> flightActions)
    {
        _flightActions = flightActions.GetEnumerator();
    }

    public Task<bool> MoveNext(CancellationToken cancellationToken)
    {
        return Task.FromResult(_flightActions.MoveNext());
    }

    public T Current => _flightActions.Current;
}

internal class MockFlightServerRecordBatchStreamWriter : FlightServerRecordBatchStreamWriter
{
    private readonly MockStreamWriter<FlightData> _streamWriter;
    public MockFlightServerRecordBatchStreamWriter() : this(new MockStreamWriter<FlightData>()) { }

    private MockFlightServerRecordBatchStreamWriter(MockStreamWriter<FlightData> clientStreamWriter) : base(clientStreamWriter)
    {
        _streamWriter = clientStreamWriter;
    }

    public IEnumerable<FlightData> FlightData => _streamWriter.Messages;

    public async Task WriteRecordBatchAsync(RecordBatch recordBatch)
    {
        await WriteAsync(recordBatch).ConfigureAwait(false);
    }
}


