﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using CommandLine;
using CommandLine.Text;
using ConsoleTables.Core;
using DocsVision.Platform.ObjectManager;
using DocsVision.Platform.ObjectManager.Metadata;

namespace Benchmark
{
	class Program
	{
		static void Main(string[] args)
		{
			var argsParsed = new Args();
			var isValid = Parser.Default.ParseArgumentsStrict(args, argsParsed, () => { Console.WriteLine(HelpText.AutoBuild(argsParsed)); });
			if (!isValid)
				return;

			var sessionManager = SessionManager.CreateInstance(argsParsed.ConnectionString);
			var sessions = new List<UserSession>();

			Console.WriteLine("Prepare sessions");
			for (int i = 0; i < argsParsed.ThreadsCount; i++)
			{
				var session = sessionManager.CreateSession();
				sessions.Add(session);
			}

			long createCardTime = 0;
			long createRowTime = 0;
			long deleteCardTime = 0;
			long getCardTime = 0;
			long deleteRowTime = 0;
			long changeRowTime = 0;
			long secondaryGetCardTime = 0;
			long batchUpdateTime = 0;

			var versionsSectionId = new Guid("F831372E-8A76-4ABC-AF15-D86DC5FFBE12");
			var tasks = new List<Task>();
			foreach (var userSession in sessions)
			{
				var task = Task.Run(() =>
				{
					Console.Write(Thread.CurrentThread.ManagedThreadId);

					var stopWatch = Stopwatch.StartNew();
					var cardData = userSession.CardManager.CreateCardData(new Guid("6E39AD2B-E930-4D20-AAFA-C2ECF812C2B3"));
					cardData.Description = "#######DELETE THIS CARD####";
					Interlocked.Add(ref createCardTime, stopWatch.ElapsedMilliseconds);

					stopWatch.Restart();
					var row = cardData.Sections[versionsSectionId].CreateRow();
					Interlocked.Add(ref createRowTime, stopWatch.ElapsedMilliseconds);

					stopWatch.Restart();
					row["VersionNumber"] = 10;
					Interlocked.Add(ref changeRowTime, stopWatch.ElapsedMilliseconds);

					stopWatch.Restart();
					cardData.Sections[versionsSectionId].DeleteRow(row.Id);
					Interlocked.Add(ref deleteRowTime, stopWatch.ElapsedMilliseconds);

					stopWatch.Restart();
					cardData.BeginUpdate();
					cardData.Sections[versionsSectionId].CreateRow()["VersionNumber"] = 10;
					cardData.EndUpdate();
					Interlocked.Add(ref batchUpdateTime, stopWatch.ElapsedMilliseconds);

					var cardId = cardData.Id;
					userSession.CardManager.PurgeCache();
					stopWatch.Restart();
					cardData = userSession.CardManager.GetCardData(cardId);
					cardData.FetchMode = FetchMode.Card;
					foreach (var tempRow in cardData.Sections[versionsSectionId].Rows)
					{

					}
					Interlocked.Add(ref getCardTime, stopWatch.ElapsedMilliseconds);

					userSession.CardManager.PurgeCache();
					stopWatch.Restart();
					cardData = userSession.CardManager.GetCardData(cardId);
					cardData.FetchMode = FetchMode.Card;
					foreach (var tempRow in cardData.Sections[versionsSectionId].Rows)
					{

					}
					Interlocked.Add(ref secondaryGetCardTime, stopWatch.ElapsedMilliseconds);

					stopWatch.Restart();
					userSession.CardManager.DeleteCard(cardData.Id);
					Interlocked.Add(ref deleteCardTime, stopWatch.ElapsedMilliseconds);
				});
				tasks.Add(task);
			}

			Task.WaitAll(tasks.ToArray());
			Console.WriteLine();
			var table = new ConsoleTable("Metric", "CreateCard", "CreateRow", "DeleteCard", "GetCard", "DeleteRow", "ChangeRow", "SecondaryGetCard", "BatchUpdateTime");
			table.AddRow("Total", createCardTime, createRowTime, deleteCardTime, getCardTime, deleteRowTime, changeRowTime, secondaryGetCardTime, batchUpdateTime);
			table.AddRow("Avg", createCardTime / argsParsed.ThreadsCount, createRowTime / argsParsed.ThreadsCount, deleteCardTime / argsParsed.ThreadsCount, getCardTime / argsParsed.ThreadsCount, deleteRowTime / argsParsed.ThreadsCount, changeRowTime / argsParsed.ThreadsCount, secondaryGetCardTime / argsParsed.ThreadsCount, batchUpdateTime / argsParsed.ThreadsCount);
			table.Write(Format.Alternative);
			Console.WriteLine("Dispose sessions");
			sessions.ForEach(x => x.Close());
		}
	}

	class Args
	{
		[Option('t', "Threads count", Required = true, DefaultValue = 10, HelpText = "Threads count")]
		public int ThreadsCount { get; set; }

		[Option('c', "Connection string", Required = true, DefaultValue = "ConnectAddress=http://localhost/docsvision/StorageServer/StorageServerService.asmx", HelpText = "DocsVision connection string")]
		public string ConnectionString { get; set; }

		[HelpVerbOption]
		public string DoHelpForVerb(string verbName)
		{
			return verbName;
		}
	}
}
