using System.Collections.Generic;
using System.Net;
using JetBrains.Annotations;
using Utf8Json;
using Webserver.Permissions;

namespace Webserver.WebAPI.APIs {
	[UsedImplicitly]
	public class Command : AbsRestApi {
		private static readonly byte[] jsonCommandsKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("commands");

		private static readonly byte[] jsonOverloadsKey = JsonWriter.GetEncodedPropertyNameWithBeginObject ("overloads");
		private static readonly byte[] jsonCommandKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("command");
		private static readonly byte[] jsonDescriptionKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("description");
		private static readonly byte[] jsonHelpKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("help");
		private static readonly byte[] jsonAllowedKey = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("allowed");
		
		protected override void HandleRestGet (RequestContext _context) {
			string id = _context.RequestPath;
			int permissionLevel = _context.PermissionLevel;
			
			PrepareEnvelopedResult (out JsonWriter writer);
			
			writer.WriteRaw (jsonCommandsKey);
			writer.WriteBeginArray ();

			if (string.IsNullOrEmpty (id)) {
				IList<IConsoleCommand> ccs = SdtdConsole.Instance.GetCommands ();
				for (int i = 0; i < ccs.Count; i++) {
					IConsoleCommand cc = ccs [i];
					
					if (i > 0) {
						writer.WriteValueSeparator ();
					}

					writeCommandJson (ref writer, cc, permissionLevel);
				}
			} else if (SdtdConsole.Instance.GetCommand (id) is { } command) {
				writeCommandJson (ref writer, command, permissionLevel);
			} else {
				writer.WriteEndArray ();
				writer.WriteEndObject ();
				SendEnvelopedResult (_context, ref writer, HttpStatusCode.NotFound);
				return;
			}

			writer.WriteEndArray ();
			writer.WriteEndObject ();

			SendEnvelopedResult (_context, ref writer);
		}

		private void writeCommandJson (ref JsonWriter _writer, IConsoleCommand _command, int _userPermissionLevel) {
			_writer.WriteRaw (jsonOverloadsKey);
			_writer.WriteBeginArray ();

			string cmd = string.Empty;
				
			string[] ses = _command.GetCommands ();
			for (int i = 0; i < ses.Length; i++) {
				string s = ses [i];
				
				if (i > 0) {
					_writer.WriteValueSeparator ();
				}

				_writer.WriteString (s);

				if (s.Length > cmd.Length) {
					cmd = s;
				}
			}

			_writer.WriteEndArray ();

			_writer.WriteRaw (jsonCommandKey);
			_writer.WriteString (cmd);
				
			_writer.WriteRaw (jsonDescriptionKey);
			_writer.WriteString (_command.GetDescription ());
				
			_writer.WriteRaw (jsonHelpKey);
			_writer.WriteString (_command.GetHelp ());
				
			int commandPermissionLevel = GameManager.Instance.adminTools.Commands.GetCommandPermissionLevel (_command.GetCommands ());
			_writer.WriteRaw (jsonAllowedKey);
			_writer.WriteBoolean (_userPermissionLevel <= commandPermissionLevel);

			_writer.WriteEndObject ();
		}

		protected override void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
			if (!TryGetJsonField (_jsonInput, "command", out string commandString)) {
				SendErrorResult (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_COMMAND");
				return;
			}

			WebCommandResult.ResultType responseType = WebCommandResult.ResultType.Full;

			if (TryGetJsonField (_jsonInput, "format", out string formatString)) {
				if (formatString.EqualsCaseInsensitive ("raw")) {
					responseType = WebCommandResult.ResultType.Raw;
				} else if (formatString.EqualsCaseInsensitive ("simple")) {
					responseType = WebCommandResult.ResultType.ResultOnly;
				}
			}

			int commandSepIndex = commandString.IndexOf (' ');
			string commandPart = commandSepIndex > 0 ? commandString.Substring (0, commandSepIndex) : commandString;
			string argumentsPart = commandSepIndex > 0
				? commandString.Substring (commandPart.Length + 1)
				: "";

			IConsoleCommand command = SdtdConsole.Instance.GetCommand (commandPart, true);

			if (command == null) {
				SendErrorResult (_context, HttpStatusCode.NotFound, _jsonInputData, "UNKNOWN_COMMAND");
				return;
			}

			int commandPermissionLevel = GameManager.Instance.adminTools.Commands.GetCommandPermissionLevel (command.GetCommands ());

			if (_context.PermissionLevel > commandPermissionLevel) {
				SendErrorResult (_context, HttpStatusCode.Forbidden, _jsonInputData, "NO_PERMISSION");
				return;
			}

			_context.Response.SendChunked = true;
			WebCommandResult wcr = new WebCommandResult (commandPart, argumentsPart, responseType, _context);
			SdtdConsole.Instance.ExecuteAsync (commandString, wcr);
		}

		public override int DefaultPermissionLevel () => AdminWebModules.PermissionLevelGuest;
	}
}