using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using FilterAPI;
using FilterAPI.CustomCurrency;
using FilterAPI.ItemExchange;
using FilterAPI.Networking;

using FilterCentral.LocalHandlers;
using FilterCentral.LocalNetworking;

namespace FilterCentral
{
	internal class Program
    {
        public static Authentication Auth;
        public static Database SQL;

        public static LocalHandlerLoader LocalHandlers;

        public static LocalClient LoginClient;
        public static LocalClient ManagerClient;
		public static LocalClient LauncherClient;
        public static Dictionary<String, LocalClient> ZoneClients = new Dictionary<String, LocalClient>();

        private static void Main(String[] Args)
        {
            Auth = new Authentication();

            Console.Title = String.Format("{0} Filter [{1}] :: SoV420 :: 2018", Auth.ConfigValues["ServerName"], Properties.Resources.BuildDate);
            WriteLine(ConsoleColor.Green, "[Central] {0} Filter successfully booted up.", Auth.ConfigValues["ServerName"]);

			SQL = new Database(Auth);

            CurrencyLoader CustomCurrency = new CurrencyLoader(Auth);
            TokenLoader ItemExchange = new TokenLoader(Auth);

			#region junk
			//if (!SQL.DatabaseExists(Auth.ConfigValues["CustomCurrencyDB"]))
			//{
			//    WriteLine(ConsoleColor.Red, "[Central]: Database not found for custom currency. Please create a database called: {0} before starting the filter.", Auth.ConfigValues["CustomCurrencyDB"]);

			//    Console.ReadLine();

			//    Environment.Exit(0);
			//}

			//foreach (Currency Currency in CustomCurrency.Currencies)
			//{
			//    WriteLine(ConsoleColor.Magenta, "[Central]: Checking if table exists in {0}: {1}.", Auth.ConfigValues["CustomCurrencyDB"], Currency.TableName);

			//    if (SQL.TableExists(Auth.ConfigValues["CustomCurrencyDB"], Currency.TableName)) { WriteLine(ConsoleColor.Green, "[Central]: Table found!"); }
			//    else
			//    {
			//        WriteLine(ConsoleColor.Red, "[Central]: Could not find table. Creating...");

			//        if (!Currency.IsCharacter) { SQL.CreateCCTable(Currency.TableName, "nUserNo"); }
			//        else { SQL.CreateCCTable(Currency.TableName, "nCharNo"); }

			//        WriteLine(ConsoleColor.Green, "[Central]: Created table for {0}.", Currency.CurrencyName);
			//    }

			//    if (Currency.HasMaximum)
			//    {
			//        WriteLine(ConsoleColor.Magenta, "[Central]: Checking if obtained column exists in {0}: {1}.", Auth.ConfigValues["CustomCurrencyDB"], Currency.TableName);

			//        if (SQL.TableHasColumn(Auth.ConfigValues["CustomCurrencyDB"], Currency.TableName, "Obtained")) { WriteLine(ConsoleColor.Green, "[Central]: Column found!"); }
			//        else
			//        {
			//            WriteLine(ConsoleColor.Red, "[Central]: Could not find column. Adding...");

			//            SQL.AddObtainedToTable(Currency.TableName);

			//            WriteLine(ConsoleColor.Green, "[Central]: Added obtained column for {0}.", Currency.CurrencyName);
			//        }
			//    }

			//    if ((CustomCurrency.CurrencyItemIDs.Where(CurrencyID => CurrencyID.CurrencyID == Currency.CurrencyID).FirstOrDefault()) == null)
			//    {
			//        WriteLine(ConsoleColor.Red, "[Central]: No items could be found for currency: {0}. Please fix this before starting the filter.", Currency.CurrencyName);

			//        Console.ReadLine();

			//        Environment.Exit(0);
			//    }
			//}

			//foreach (Token Token in ItemExchange.TokenInfo)
			//{
			//    WriteLine(ConsoleColor.Magenta, "[Central]: Checking if table exists in {0}: {1}.", Auth.ConfigValues["CustomCurrencyDB"], Token.TableName);

			//    if (SQL.TableExists(Auth.ConfigValues["CustomCurrencyDB"], Token.TableName)) { WriteLine(ConsoleColor.Green, "[Central]: Table found!"); }
			//    else
			//    {
			//        WriteLine(ConsoleColor.Red, "[Central]: Could not find table. Creating...");

			//        if (!Token.IsCharacter) { SQL.CreateCCTable(Token.TableName, "nUserNo"); }
			//        else { SQL.CreateCCTable(Token.TableName, "nCharNo"); }

			//        WriteLine(ConsoleColor.Green, "[Central]: Created table for {0}.", Token.TableName);
			//    }

			//    if ((ItemExchange.TokenItemIDs.Where(TokenID => TokenID.TokenID == Token.TokenID).FirstOrDefault()) == null)
			//    {
			//        WriteLine(ConsoleColor.Red, "[Central]: No items could be found for currency: {0}. Please fix this before starting the filter.", Token.TokenName);

			//        Console.ReadLine();

			//        Environment.Exit(0);
			//    }
			//}
			#endregion

			LocalListener LListen = new LocalListener();

            LocalHandlers = new LocalHandlerLoader();
			// be sure that server is not in maintenance ?????
			if(SQL.GetbInMaintenanceFornServerID(0))
			{
				WriteLine(ConsoleColor.DarkRed, "INFO: Server currently in maintenance mode.\nOnly staff will be able to log in.");
				//SQL.SetbInMaintenanceFornServerID(0, false);
			}
			Console.ResetColor();
            ReadCommand();
        }

		private static async Task MaintenanceOperation(int TimeToBeginInMinutes)
		{
			int minuteCounter = TimeToBeginInMinutes + 1;
			for (int mins = TimeToBeginInMinutes; mins <= minuteCounter; mins--)
			{
				minuteCounter--;
				if (minuteCounter == 1)
				{
					SendWorldMessage("Server going down for maintenance in 1 minute");
					await Task.Delay(15000);
					SendWorldMessage("Server shutting down in 45 seconds");
					await Task.Delay(15000);
					SendWorldMessage("Server shutting down in 30 seconds");
					await Task.Delay(15000);
					SendWorldMessage("Server shutting down in 15 seconds");
					await Task.Delay(15000);
					break;
				}
				SendWorldMessage($"Server shutting down in {minuteCounter} minutes");
				await Task.Delay(60000);
			}
			List<string> OnlinePlayers = SQL.GetOnlinesIDs();
			for (var i = 0; i < OnlinePlayers.Count; i++)
			{
				var playersID = OnlinePlayers[i];
				var playernUserNo = SQL.GetnUserNoFromsID(playersID);
				var playernAuthID = SQL.GetnAuthIDFromnEMID(playernUserNo);
				var playernTypeID = SQL.GetnTypeIDfromnAuthID(playernAuthID, out bool nLoginable);
				if (playernTypeID != 1)
				{
					using (var LocalPacket = new Packet(4, 7))
					{
							LocalPacket.PacketWriter.Write(playersID);
							LocalPacket.PacketWriter.Write(true);
							LocalPacket.PacketWriter.Write("Server");
							LocalPacket.PacketWriter.Write("Disconnected for server maintenance");

							ManagerClient.SendPacket(LocalPacket);
					}
				}
			}
			WriteLine(ConsoleColor.Cyan, "Maintenance task complete!");
		}

		private static void ReadCommand()
        {
            String Text = Console.ReadLine();

            String[] TextSplit = Text.Split(' ');

			String Command = TextSplit[0].ToLower();
			String Argument;
			String Argument2;
			try { Argument = TextSplit[1].ToLower();}
			catch { Argument = String.Empty;}
			try { Argument2 = TextSplit[2].ToLower(); }
			catch { Argument2 = null; }

			switch (Command)
			{
				case "reload":
					using (var LocalPacket = new Packet(2, 4))
					{
						foreach (LocalClient ZClient in ZoneClients.Values) { ZClient.SendPacket(LocalPacket); }
						ManagerClient.SendPacket(LocalPacket);
					}

					WriteLine(ConsoleColor.Green, $"Reload has been sent to the manager and {ZoneClients.Values.Count()} zones.");
					break;
				case "maintenance":
					Byte ServerID = 0;
					Boolean Maint = SQL.GetbInMaintenanceFornServerID(ServerID);
					int TimeToMaintInMinutes = 3; // default maint time
					switch (Argument)
					{
						case "status":
							WriteLine(ConsoleColor.Blue, $"Status: {Maint}");
							break;
						case "on": // turn on maint mode
							int arg2;
							if (Argument2 != null && int.TryParse(Argument2, out arg2)) { TimeToMaintInMinutes = arg2; }
							if (!Maint)
							{
								SQL.SetbInMaintenanceFornServerID(ServerID, true);
								WriteLine(ConsoleColor.Cyan, $"Server {ServerID} now in maintenance mode.");
								WriteLine(ConsoleColor.Cyan, $"Starting maintenance announcement timer.");
								Task MaintTask = MaintenanceOperation(TimeToMaintInMinutes);
							}
							else { WriteLine(ConsoleColor.Blue, $"Server {ServerID} already in maintenance mode."); }
							break;
						case "off":
							if (Maint)
							{
								SQL.SetbInMaintenanceFornServerID(ServerID, false);
								WriteLine(ConsoleColor.Cyan, $"Server {ServerID} now out of maintenance mode.");
							}
							else { WriteLine(ConsoleColor.Blue, $"Server {ServerID} already out of maintenance mode."); }
							break;
						default:
							WriteLine(ConsoleColor.Cyan, @"Usage: maintenance {status | on | off}");
							break;
					}
					break;
				default:
					WriteLine(ConsoleColor.Red, $"Unrecognized command `{Command}`");
					break;
			}

            ReadCommand();
        }

		public static void WriteLine(ConsoleColor Color, String Text)
		{
			var lastcolor = Console.ForegroundColor;
			Console.ForegroundColor = Color;
			Console.WriteLine(Text);
			Console.ForegroundColor = lastcolor;
		}

		public static void WriteLine(ConsoleColor Color, String Text, params Object[] Args)
        {
            String FormattedText = String.Format(Text, Args);
			var lastcolor = Console.ForegroundColor;
            Console.ForegroundColor = Color;
            Console.WriteLine(FormattedText);
			Console.ForegroundColor = lastcolor;
		}

		public static void SendWorldMessage(String message)
		{
			using (var LocalPacket = new Packet(4, 8))
			{
				LocalPacket.PacketWriter.Write((Byte)1);
				LocalPacket.PacketWriter.Write("");
				LocalPacket.PacketWriter.Write(message);

				ManagerClient.SendPacket(LocalPacket);
			}
		}
    }
}
