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

namespace Examples {
	[UsedImplicitly]
	public class Markers : AbsRestApi {
		private const int numRandomMarkers = 5;

		private const string defaultIcon =
			"https://upload.wikimedia.org/wikipedia/commons/thumb/1/11/Blue_question_mark_icon.svg/1200px-Blue_question_mark_icon.svg.png";
		
		private readonly Dictionary<string, (int, int, string)> markers = new Dictionary<string, (int, int, string)> ();

		public Markers () {
			GameRandom random = GameRandomManager.Instance.CreateGameRandom ();
			
			for (int i = 0; i < numRandomMarkers; i++) {
				int x = random.RandomRange (-1000, 1001);
				int y = random.RandomRange (-1000, 1001);

				markers.Add (WebUtils.GenerateGuid (), (x, y, null));
			}
			
			GameRandomManager.Instance.FreeGameRandom (random);
		}

		private static readonly byte[] jsonKeyId = JsonWriter.GetEncodedPropertyNameWithBeginObject ("id");
		private static readonly byte[] jsonKeyX = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("x");
		private static readonly byte[] jsonKeyY = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("y");
		private static readonly byte[] jsonKeyIcon = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("icon");

		protected override void HandleRestGet (RequestContext _context) {
			string id = _context.RequestPath;
			
			PrepareEnvelopedResult (out JsonWriter writer);
			
			if (string.IsNullOrEmpty (id)) {
				writer.WriteBeginArray ();

				bool first = true;
				foreach ((string markerId, (int, int, string) properties) in markers) {
					if (!first) {
						writer.WriteValueSeparator ();
					}
					
					first = false;
					
					writeMarkerJson (ref writer, markerId, properties);
				}

				writer.WriteEndArray ();
				SendEnvelopedResult (_context, ref writer);
				return;
			}

			if (!markers.TryGetValue (id, out (int, int, string) properties2)) {
				writer.WriteRaw (WebUtils.JsonEmptyData);
				SendEnvelopedResult (_context, ref writer, HttpStatusCode.NotFound);
				return;
			}

			{
				writer.WriteBeginArray ();
				
				writeMarkerJson (ref writer, id, properties2);
				
				writer.WriteEndArray ();
				SendEnvelopedResult (_context, ref writer);
			}
		}

		private void writeMarkerJson (ref JsonWriter _writer, string _markerId, (int, int, string) _properties) {
			_writer.WriteRaw (jsonKeyId);
			_writer.WriteString (_markerId);
			_writer.WriteRaw (jsonKeyX);
			(int x, int y, string icon) = _properties;
			_writer.WriteInt32 (x);
			_writer.WriteRaw (jsonKeyY);
			_writer.WriteInt32 (y);
			_writer.WriteRaw (jsonKeyIcon);
			_writer.WriteString (icon ?? defaultIcon);
			_writer.WriteEndObject ();
		}

		protected override void HandleRestPost (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
			if (!JsonCommons.TryGetJsonField (_jsonInput, "x", out int x)) {
				SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_X");
				return;
			}

			if (!JsonCommons.TryGetJsonField (_jsonInput, "y", out int y)) {
				SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_Y");
				return;
			}

			JsonCommons.TryGetJsonField (_jsonInput, "icon", out string icon);
			if (string.IsNullOrEmpty (icon)) {
				icon = null;
			}

			string newId = WebUtils.GenerateGuid ();
			markers.Add (newId, (x, y, icon));

			PrepareEnvelopedResult (out JsonWriter writer);
			writer.WriteString (newId);
			SendEnvelopedResult (_context, ref writer, HttpStatusCode.Created);
		}

		protected override void HandleRestPut (RequestContext _context, IDictionary<string, object> _jsonInput, byte[] _jsonInputData) {
			if (!JsonCommons.TryGetJsonField (_jsonInput, "x", out int x)) {
				SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_X");
				return;
			}

			if (!JsonCommons.TryGetJsonField (_jsonInput, "y", out int y)) {
				SendEmptyResponse (_context, HttpStatusCode.BadRequest, _jsonInputData, "NO_OR_INVALID_Y");
				return;
			}

			bool keepIcon = !_jsonInput.TryGetValue ("icon", out _);
			JsonCommons.TryGetJsonField (_jsonInput, "icon", out string icon);
			if (string.IsNullOrEmpty (icon)) {
				icon = null;
			}

			string id = _context.RequestPath;

			if (!markers.TryGetValue (id, out (int, int, string) properties)) {
				SendEmptyResponse (_context, HttpStatusCode.NotFound, _jsonInputData, "ID_NOT_FOUND");
				return;
			}

			if (keepIcon) {
				icon = properties.Item3;
			}
			markers [id] = (x, y, icon);

			PrepareEnvelopedResult (out JsonWriter writer);
			writer.WriteRaw (jsonKeyId);
			writer.WriteString (id);
			writer.WriteRaw (jsonKeyX);
			writer.WriteInt32 (x);
			writer.WriteRaw (jsonKeyY);
			writer.WriteInt32 (y);
			writer.WriteRaw (jsonKeyIcon);
			writer.WriteString (icon);
			writer.WriteEndObject ();
			SendEnvelopedResult (_context, ref writer);
		}

		protected override void HandleRestDelete (RequestContext _context) {
			string id = _context.RequestPath;

			SendEmptyResponse (_context, markers.Remove (id) ? HttpStatusCode.NoContent : HttpStatusCode.NotFound);
		}
		
		public override int[] DefaultMethodPermissionLevels () => new[] {
			AdminWebModules.MethodLevelNotSupported,
			AdminWebModules.PermissionLevelGuest,
			AdminWebModules.PermissionLevelUser,
			AdminWebModules.MethodLevelInheritGlobal,
			AdminWebModules.MethodLevelInheritGlobal
		};
	}
}