#if OLEDB
using System;
using System.Data.OleDb;
using System.Linq;
using Xunit;

namespace Dapper.Tests
{
    public class OLDEBTests : TestBase
    {
        public static string OleDbConnectionString =>
            IsAppVeyor
                ? @"Provider=SQLOLEDB;Data Source=(local)\SQL2014;Initial Catalog=tempdb;User Id=sa;Password=Password12!"
                : "Provider=SQLOLEDB;Data Source=.;Initial Catalog=tempdb;Integrated Security=SSPI";

        public OleDbConnection GetOleDbConnection()
        {
            var conn = new OleDbConnection(OleDbConnectionString);
            conn.Open();
            return conn;
        }

        // see https://stackoverflow.com/q/18847510/23354
        [Fact]
        public void TestOleDbParameters()
        {
            using (var conn = GetOleDbConnection())
            {
                var row = conn.Query("select Id = ?, Age = ?",
                    new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
                ).Single();
                int age = row.Age;
                int id = row.Id;
                age.IsEqualTo(23);
                id.IsEqualTo(12);
            }
        }

        [Fact]
        public void PseudoPositionalParameters_Simple()
        {
            using (var connection = GetOleDbConnection())
            {
                int value = connection.Query<int>("select ?x? + ?y_2? + ?z?", new { x = 1, y_2 = 3, z = 5, z2 = 24 }).Single();
                value.IsEqualTo(9);
            }
        }

        [Fact]
        public void Issue601_InternationalParameterNamesWork_OleDb()
        {
            // pseudo-positional
            using (var connection = GetOleDbConnection())
            {
                int value = connection.QuerySingle<int>("select ?æøå٦?", new { æøå٦ = 42 });
            }
        }

        [Fact]
        public void PseudoPositionalParameters_Dynamic()
        {
            using (var connection = GetOleDbConnection())
            {
                var args = new DynamicParameters();
                args.Add("x", 1);
                args.Add("y_2", 3);
                args.Add("z", 5);
                args.Add("z2", 24);
                int value = connection.Query<int>("select ?x? + ?y_2? + ?z?", args).Single();
                value.IsEqualTo(9);
            }
        }

        [Fact]
        public void PseudoPositionalParameters_ReusedParameter()
        {
            using (var connection = GetOleDbConnection())
            {
                try
                {
                    int value = connection.Query<int>("select ?x? + ?y_2? + ?x?", new { x = 1, y_2 = 3 }).Single();
                    Assert.Fail();
                }
                catch (InvalidOperationException ex)
                {
                    ex.Message.IsEqualTo("When passing parameters by position, each parameter can only be referenced once");
                }
            }
        }

        [Fact]
        public void Issue569_SO38527197_PseudoPositionalParameters_In()
        {
            using (var connection = GetOleDbConnection())
            {
                int[] ids = { 1, 2, 5, 7 };
                var list = connection.Query<int>("select * from string_split('1,2,3,4,5',',') where value in ?ids?", new { ids }).AsList();
                list.Sort();
                string.Join(",", list).IsEqualTo("1,2,5");
            }
        }

        [Fact]
        public void PseudoPositional_CanUseVariable()
        {
            using (var connection = GetOleDbConnection())
            {
                const int id = 42;
                var row = connection.QuerySingle("declare @id int = ?id?; select @id as [A], @id as [B];", new { id });
                int a = (int)row.A;
                int b = (int)row.B;
                a.IsEqualTo(42);
                b.IsEqualTo(42);
            }
        }

        [Fact]
        public void PseudoPositional_CannotUseParameterMultipleTimes()
        {
            using (var connection = GetOleDbConnection())
            {
                try
                {
                    const int id = 42;
                    var row = connection.QuerySingle("select ?id? as [A], ?id? as [B];", new { id });
                    Assert.Fail();
                }
                catch (InvalidOperationException ex) when (ex.Message == "When passing parameters by position, each parameter can only be referenced once")
                {
                    // that's a win
                }
            }
        }

        [Fact]
        public void PseudoPositionalParameters_ExecSingle()
        {
            using (var connection = GetOleDbConnection())
            {
                var data = new { x = 6 };
                connection.Execute("create table #named_single(val int not null)");
                int count = connection.Execute("insert #named_single (val) values (?x?)", data);
                int sum = (int)connection.ExecuteScalar("select sum(val) from #named_single");
                count.IsEqualTo(1);
                sum.IsEqualTo(6);
            }
        }

        [Fact]
        public void PseudoPositionalParameters_ExecMulti()
        {
            using (var connection = GetOleDbConnection())
            {
                var data = new[]
                {
                    new { x = 1, y = 1 },
                    new { x = 3, y = 1 },
                    new { x = 6, y = 1 },
                };
                connection.Execute("create table #named_multi(val int not null)");
                int count = connection.Execute("insert #named_multi (val) values (?x?)", data);
                int sum = (int)connection.ExecuteScalar("select sum(val) from #named_multi");
                count.IsEqualTo(3);
                sum.IsEqualTo(10);
            }
        }

        [Fact]
        public void Issue457_NullParameterValues()
        {
            const string sql = @"
DECLARE @since DATETIME, @customerCode nvarchar(10)
SET @since = ? -- ODBC parameter
SET @customerCode = ? -- ODBC parameter

SELECT @since as [Since], @customerCode as [Code]";

            using (var connection = GetOleDbConnection())
            {
                DateTime? since = null; // DateTime.Now.Date;
                const string code = null;  // "abc";
                var row = connection.QuerySingle(sql, new
                {
                    since,
                    customerCode = code
                });
                var a = (DateTime?)row.Since;
                var b = (string)row.Code;

                a.IsEqualTo(since);
                b.IsEqualTo(code);
            }
        }

        [Fact]
        public void Issue457_NullParameterValues_Named()
        {
            const string sql = @"
DECLARE @since DATETIME, @customerCode nvarchar(10)
SET @since = ?since? -- ODBC parameter
SET @customerCode = ?customerCode? -- ODBC parameter

SELECT @since as [Since], @customerCode as [Code]";

            using (var connection = GetOleDbConnection())
            {
                DateTime? since = null; // DateTime.Now.Date;
                const string code = null;  // "abc";
                var row = connection.QuerySingle(sql, new
                {
                    since,
                    customerCode = code
                });
                var a = (DateTime?)row.Since;
                var b = (string)row.Code;

                a.IsEqualTo(since);
                b.IsEqualTo(code);
            }
        }

        [Fact]
        public async void Issue457_NullParameterValues_MultiAsync()
        {
            const string sql = @"
DECLARE @since DATETIME, @customerCode nvarchar(10)
SET @since = ? -- ODBC parameter
SET @customerCode = ? -- ODBC parameter

SELECT @since as [Since], @customerCode as [Code]";

            using (var connection = GetOleDbConnection())
            {
                DateTime? since = null; // DateTime.Now.Date;
                const string code = null;  // "abc";
                using (var multi = await connection.QueryMultipleAsync(sql, new
                {
                    since,
                    customerCode = code
                }).ConfigureAwait(false))
                {
                    var row = await multi.ReadSingleAsync().ConfigureAwait(false);
                    var a = (DateTime?)row.Since;
                    var b = (string)row.Code;

                    a.IsEqualTo(since);
                    b.IsEqualTo(code);
                }
            }
        }

        [Fact]
        public async void Issue457_NullParameterValues_MultiAsync_Named()
        {
            const string sql = @"
DECLARE @since DATETIME, @customerCode nvarchar(10)
SET @since = ?since? -- ODBC parameter
SET @customerCode = ?customerCode? -- ODBC parameter

SELECT @since as [Since], @customerCode as [Code]";

            using (var connection = GetOleDbConnection())
            {
                DateTime? since = null; // DateTime.Now.Date;
                const string code = null;  // "abc";
                using (var multi = await connection.QueryMultipleAsync(sql, new
                {
                    since,
                    customerCode = code
                }).ConfigureAwait(false))
                {
                    var row = await multi.ReadSingleAsync().ConfigureAwait(false);
                    var a = (DateTime?)row.Since;
                    var b = (string)row.Code;

                    a.IsEqualTo(since);
                    b.IsEqualTo(code);
                }
            }
        }
    }
}
#endif