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

namespace Webserver.Commands {
	[UsedImplicitly]
	public class WebPermissionsCmd : ConsoleCmdAbstract {
		protected override string[] getCommands () {
			return new[] {"webpermission"};
		}

		protected override string getDescription () {
			return "Manage web permission levels";
		}

		protected override string getHelp () {
			return @"
				|Set/get permission levels required to access a given web functionality. Default
			    |level required for functions that are not explicitly specified is 0.
			    |Usage:
				|   1. webpermission add <webfunction> <method> <level>
			    |   2. webpermission remove <webfunction>
			    |   3. webpermission list [includedefaults]
				|1. Add a new override (or replace the existing one) for the given function. Method must be a HTTP method (like 'GET', 'POST')
						supported by the function or the keyword 'global' for a per-API permission level. Use the permission level keyword
						'inherit' to use the per-API permission level for the specified method instead of a custom one for just the single method.
				|2. Removes any custom overrides for the specified function.
				|3. List all permissions. Pass in 'true' for the includedefaults argument to also show functions that do not have a custom override defined.
				".Unindent ();
		}

		public override void Execute (List<string> _params, CommandSenderInfo _senderInfo) {
			if (_params.Count >= 1) {
				if (_params [0].EqualsCaseInsensitive ("add")) {
					ExecuteAdd (_params);
				} else if (_params [0].EqualsCaseInsensitive ("remove")) {
					ExecuteRemove (_params);
				} else if (_params [0].EqualsCaseInsensitive ("list")) {
					ExecuteList (_params);
				} else {
					SdtdConsole.Instance.Output ($"Invalid sub command \"{_params [0]}\".");
				}
			} else {
				SdtdConsole.Instance.Output ("No sub command given.");
			}
		}

		private void ExecuteAdd (List<string> _params) {
			if (_params.Count != 4) {
				SdtdConsole.Instance.Output ($"Wrong number of arguments, expected 4, found {_params.Count}.");
				return;
			}

			string moduleString = _params [1];
			string methodString = _params [2];
			string permissionLevelString = _params [3];

			ERequestMethod method = ERequestMethod.Count;
			bool isGlobal = false;
			bool isInherit = false;
			int level;
			
			if (!AdminWebModules.Instance.IsKnownModule (moduleString)) {
				SdtdConsole.Instance.Output ($"\"{moduleString}\" is not a valid web function.");
				return;
			}

			AdminWebModules.WebModule module = AdminWebModules.Instance.GetModule (moduleString);

			if (methodString.EqualsCaseInsensitive ("global")) {
				isGlobal = true;
			} else {
				if (!EnumUtils.TryParse (methodString, out method, true)) {
					SdtdConsole.Instance.Output ($"\"{methodString}\" is neither a valid HTTP method nor the 'global' keyword.");
					return;
				}

				if (module.LevelPerMethod == null || module.LevelPerMethod [(int)method] == AdminWebModules.MethodLevelNotSupported) {
					SdtdConsole.Instance.Output ($"\"{methodString}\" is not a method supported by the \"{moduleString}\" function.");
					return;
				}
			}

			if (permissionLevelString.EqualsCaseInsensitive ("inherit")) {
				if (isGlobal) {
					SdtdConsole.Instance.Output ($"Permission level can not use the 'inherit' keyword with the 'global' method keyword.");
					return;
				}
				
				isInherit = true;
				level = AdminWebModules.MethodLevelInheritGlobal;
			} else {
				if (!int.TryParse (permissionLevelString, out level)) {
					SdtdConsole.Instance.Output ($"\"{permissionLevelString}\" is neither a valid integer nor the 'inherit' keyword.");
					return;
				}
			}

			module.IsDefault = false;
			if (isGlobal) {
				module.LevelGlobal = level;
			} else {
				module.LevelPerMethod [(int)method] = level;
			}
			
			AdminWebModules.Instance.AddModule (module);
			
			SdtdConsole.Instance.Output (
				$"{moduleString}, method {methodString} added {(isInherit ? ", inheriting the APIs global permission level" : "with permission level " + level)}.");
		}

		private void ExecuteRemove (List<string> _params) {
			if (_params.Count != 2) {
				SdtdConsole.Instance.Output ($"Wrong number of arguments, expected 2, found {_params.Count}.");
				return;
			}

			if (!AdminWebModules.Instance.IsKnownModule (_params [1])) {
				SdtdConsole.Instance.Output ($"\"{_params [1]}\" is not a valid web function.");
				return;
			}

			AdminWebModules.Instance.RemoveModule (_params [1]);
			SdtdConsole.Instance.Output ($"{_params [1]} removed from permissions list.");
		}

		private void ExecuteList (List<string> _params) {
			bool includeDefaults = _params.Count > 1 && ConsoleHelper.ParseParamBool (_params [1], true);
			
			SdtdConsole.Instance.Output ("Defined web function permissions:");
			
			List<AdminWebModules.WebModule> wmps = AdminWebModules.Instance.GetModules ();
			for (int iModule = 0; iModule < wmps.Count; iModule++) {
				AdminWebModules.WebModule wmp = wmps [iModule];

				if (!includeDefaults && wmp.IsDefault) {
					continue;
				}

				SdtdConsole.Instance.Output ($"  {wmp.Name,-25}: {wmp.LevelGlobal,4}{(wmp.IsDefault ? " (default permissions)" : "")}");
				if (wmp.LevelPerMethod != null) {
					for (int iMethod = 0; iMethod < wmp.LevelPerMethod.Length; iMethod++) {
						int methodLevel = wmp.LevelPerMethod [iMethod];
						ERequestMethod method = (ERequestMethod)iMethod;
						
						if (methodLevel == AdminWebModules.MethodLevelNotSupported) {
							continue;
						}
						
						if (methodLevel == AdminWebModules.MethodLevelInheritGlobal) {
							SdtdConsole.Instance.Output ($"  {method.ToStringCached (),25}: {wmp.LevelGlobal,4} (Using API level)");
						} else {
							SdtdConsole.Instance.Output ($"  {method.ToStringCached (),25}: {methodLevel,4}");
						}
					}
				}
			}
		}
	}
}