using System;
using System.Collections.Generic;
using System.Globalization;
using UnityEngine;
using Utf8Json;

namespace Webserver.WebAPI {
	public static class JsonCommons {
		private static readonly byte[] jsonKeyPositionX = JsonWriter.GetEncodedPropertyNameWithBeginObject ("x");
		private static readonly byte[] jsonKeyPositionY = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("y");
		private static readonly byte[] jsonKeyPositionZ = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("z");

		public static void WriteVector3I (ref JsonWriter _writer, Vector3i _position) {
			_writer.WriteRaw (jsonKeyPositionX);
			_writer.WriteInt32 (_position.x);
			
			_writer.WriteRaw (jsonKeyPositionY);
			_writer.WriteInt32 (_position.y);
			
			_writer.WriteRaw (jsonKeyPositionZ);
			_writer.WriteInt32 (_position.z);
			
			_writer.WriteEndObject ();
		}

		public static void WriteVector3 (ref JsonWriter _writer, Vector3 _position) {
			_writer.WriteRaw (jsonKeyPositionX);
			_writer.WriteSingle (_position.x);
			
			_writer.WriteRaw (jsonKeyPositionY);
			_writer.WriteSingle (_position.y);
			
			_writer.WriteRaw (jsonKeyPositionZ);
			_writer.WriteSingle (_position.z);
			
			_writer.WriteEndObject ();
		}

		public static void WriteVector2I (ref JsonWriter _writer, Vector2i _position) {
			_writer.WriteRaw (jsonKeyPositionX);
			_writer.WriteInt32 (_position.x);
			
			_writer.WriteRaw (jsonKeyPositionY);
			_writer.WriteInt32 (_position.y);
			
			_writer.WriteEndObject ();
		}

		public static void WriteVector2 (ref JsonWriter _writer, Vector2 _position) {
			_writer.WriteRaw (jsonKeyPositionX);
			_writer.WriteSingle (_position.x);
			
			_writer.WriteRaw (jsonKeyPositionY);
			_writer.WriteSingle (_position.y);
			
			_writer.WriteEndObject ();
		}

		private static readonly byte[] jsonKeyDays = JsonWriter.GetEncodedPropertyNameWithBeginObject ("days");
		private static readonly byte[] jsonKeyHours = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("hours");
		private static readonly byte[] jsonKeyMinutes = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("minutes");

		public static void WriteGameTimeObject (ref JsonWriter _writer, int _days, int _hours, int _minutes) {
			_writer.WriteRaw (jsonKeyDays);
			_writer.WriteInt32 (_days);
			
			_writer.WriteRaw (jsonKeyHours);
			_writer.WriteInt32 (_hours);
			
			_writer.WriteRaw (jsonKeyMinutes);
			_writer.WriteInt32 (_minutes);
			
			_writer.WriteEndObject ();
		}

		private static readonly byte[] jsonKeyCombinedString = JsonWriter.GetEncodedPropertyNameWithBeginObject ("combinedString");
		private static readonly byte[] jsonKeyPlatformId = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("platformId");
		private static readonly byte[] jsonKeyUserId = JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator ("userId");

		public static void WritePlatformUserIdentifier (ref JsonWriter _writer, PlatformUserIdentifierAbs _userIdentifier) {
			if (_userIdentifier == null) {
				_writer.WriteNull ();
				return;
			}
			
			_writer.WriteRaw (jsonKeyCombinedString);
			_writer.WriteString (_userIdentifier.CombinedString);
			
			_writer.WriteRaw (jsonKeyPlatformId);
			_writer.WriteString (_userIdentifier.PlatformIdentifierString);
			
			_writer.WriteRaw (jsonKeyUserId);
			_writer.WriteString (_userIdentifier.ReadablePlatformUserIdentifier);
			
			_writer.WriteEndObject ();
		}

		public static bool TryReadPlatformUserIdentifier (IDictionary<string, object> _jsonInput, out PlatformUserIdentifierAbs _userIdentifier) {
			if (TryGetJsonField (_jsonInput, "combinedString", out string combinedString)) {
				_userIdentifier = PlatformUserIdentifierAbs.FromCombinedString (combinedString, false);
				if (_userIdentifier != null) {
					return true;
				}
			}
			
			if (!TryGetJsonField (_jsonInput, "platformId", out string platformId)) {
				_userIdentifier = default;
				return false;
			}

			if (!TryGetJsonField (_jsonInput, "userId", out string userId)) {
				_userIdentifier = default;
				return false;
			}

			_userIdentifier = PlatformUserIdentifierAbs.FromPlatformAndId (platformId, userId, false);
			return _userIdentifier != null;
		}

		public static void WriteDateTime (ref JsonWriter _writer, DateTime _dateTime) {
			_writer.WriteString (_dateTime.ToString ("o"));
		}

		public static bool TryReadDateTime (IDictionary<string, object> _jsonInput, string _fieldName, out DateTime _result) {
			_result = default;
			
			if (!TryGetJsonField (_jsonInput, _fieldName, out string dateTimeString)) {
				return false;
			}

			return DateTime.TryParse (dateTimeString, null, DateTimeStyles.RoundtripKind, out _result);
		}


		public static bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out int _value) {
			_value = default;
			
			if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
				return false;
			}

			if (fieldNode is not double value) {
				return false;
			}

			try {
				_value = (int)value;
				return true;
			} catch (Exception) {
				return false;
			}
		}

		public static bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out double _value) {
			_value = default;
			
			if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
				return false;
			}

			if (fieldNode is not double value) {
				return false;
			}

			try {
				_value = value;
				return true;
			} catch (Exception) {
				return false;
			}
		}

		public static bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName, out string _value) {
			_value = default;
			
			if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
				return false;
			}

			if (fieldNode is not string value) {
				return false;
			}

			try {
				_value = value;
				return true;
			} catch (Exception) {
				return false;
			}
		}

		public static bool TryGetJsonField (IDictionary<string, object> _jsonObject, string _fieldName,
			out IDictionary<string, object> _value) {
			_value = default;
			
			if (!_jsonObject.TryGetValue (_fieldName, out object fieldNode)) {
				return false;
			}

			if (fieldNode is not IDictionary<string, object> value) {
				return false;
			}

			try {
				_value = value;
				return true;
			} catch (Exception) {
				return false;
			}
		}
	}
}