// counters
// number of exceptions 
var inputExceptions = new ConcurrentQueue<Exception>();
var outputExceptions = new ConcurrentQueue<Exception>();

// time for each operation - in seconds
var inputTime = new ConcurrentQueue<double>();
var outputTime = new ConcurrentQueue<double>();

// keys created in cache
var keysCreated = new ConcurrentQueue<int>();
var keysReceived = new ConcurrentQueue<int>();

// initial number of orders that will be created
const int numberOrders = 1000000;
var random = new Random();

// creating client configuration
var clientConfiguration = new IgniteClientConfiguration
{
    Endpoints = new List<string>
    {
        "localhost"
    }
};

using (var igniteClient = Ignition.StartClient(clientConfiguration))
{

    // defining cache structure
    var cacheClient = igniteClient.GetOrCreateCache<int, OrderCacheEntity>("order");

    // removing all items from cache before add new items
    cacheClient.RemoveAll();

    // adding items to the cache
    Console.WriteLine("Adding keys in cache...");

    Parallel.For(0, numberOrders, index =>
    {
        var stopWatch = new Stopwatch();
        stopWatch.Start();

        try
        {
            var item = new OrderCacheEntity
            {
                Id = index,
                Items = new List<ItemCacheEntity>
                {
                    new ItemCacheEntity
                    {
                        Id = index * 10,
                        OrderId = index,
                        Quantity = random.Next(),
                        Value = (decimal) random.NextDouble()
                    }
                }
            };

            cacheClient.Put(index, item);
            keysCreated.Enqueue(index);

            Console.WriteLine($"... (INPUT) ==> orderId {item.Id} ");
        }
        catch (Exception ex)
        {
            inputExceptions.Enqueue(ex);
        }

        stopWatch.Stop();
        inputTime.Enqueue(stopWatch.Elapsed.TotalSeconds);
    });

    Console.WriteLine(" ");

    // getting items from cache
    Console.WriteLine("Getting keys from cache...");

    Parallel.For(0, numberOrders, index =>
    {
        var stopWatch = new Stopwatch();
        stopWatch.Start();

        try
        {
            if (cacheClient.TryGet(index, out var order))
            {
                keysReceived.Enqueue(index);
                Console.WriteLine($"... (OUTPUT) ==> orderId {order.Id}");
            }

        }
        catch (Exception ex)
        {
            outputExceptions.Enqueue(ex);
        }

        stopWatch.Stop();
        outputTime.Enqueue(stopWatch.Elapsed.TotalSeconds);
    });
}

Console.WriteLine(" ");
Console.WriteLine(" ");
Console.WriteLine("-------------------------------------------");
Console.WriteLine("Time: ");
Console.WriteLine("-------------------------------------------");
Console.WriteLine($"INPUT  time (AVG seconds): {inputTime.Average()}");
Console.WriteLine($"OUTPUT time (AVG seconds): {outputTime.Average()}");
Console.WriteLine($"INPUT  time (MAX seconds): {inputTime.Max()}");
Console.WriteLine($"OUTPUT time (MAX seconds): {outputTime.Max()}");
Console.WriteLine($"INPUT  time (MIN seconds): {inputTime.Min()}");
Console.WriteLine($"OUTPUT time (MIN seconds): {outputTime.Min()}");
Console.WriteLine("-------------------------------------------");
Console.WriteLine(" ");
Console.WriteLine("-------------------------------------------");
Console.WriteLine("Exceptions: ");
Console.WriteLine("-------------------------------------------");
Console.WriteLine($"INPUT ERROR  (total): {inputExceptions.Count}");
Console.WriteLine($"OUTPUT ERROR (total): {outputExceptions.Count}");
Console.WriteLine("-------------------------------------------");
Console.WriteLine(" ");
Console.WriteLine("-------------------------------------------");
Console.WriteLine("Summary: ");
Console.WriteLine("-------------------------------------------");
Console.WriteLine($"ITEMS CREATED  (total): {keysCreated.Count}");
Console.WriteLine($"ITEMS RECEIVED (total): {keysReceived.Count}");
Console.WriteLine($"ITEMS MISSING  (total): {keysCreated.Count - keysReceived.Count}");
Console.WriteLine("-------------------------------------------");
Console.WriteLine(" ");