using System.Collections.Generic;
using Domain.Input;
using Extensions;
using UnityEngine;

namespace Domain {
	public class KeyHistory {
		private readonly LimitedSizeList<int> _lastPresses = new(10);
		private readonly LimitedSizeList<int> _lastPressesWithSpecial = new(20);

		private const int AlphabetSize = 26;
		private const int CustomKeysSize = 4;
		private const int SpecialKeysSize = 1;

		private readonly int[] _customKeys = {
			VKeyCode.Cedilla,
			VKeyCode.Interpunct,
			VKeyCode.AccentClosed,
			VKeyCode.AccentOpen
		};
		private readonly int[] _specialKeys = { VKeyCode.Shift };
		private readonly bool[] _isPressed = new bool[AlphabetSize + CustomKeysSize + SpecialKeysSize];
		private readonly bool[] _wasPressed = new bool[AlphabetSize + CustomKeysSize + SpecialKeysSize];

		public void KeyPressed(int key, bool isSpecial = false) {
			if (!isSpecial)
				_lastPresses.Add(key);
			_lastPressesWithSpecial.Add(key);
		}

		public void CheckPresses() {
			const int aIndex = 0x41;
			const int zIndex = 0x5A;

			for (int i = aIndex, j = 0; i <= zIndex; i++, j++) {
				_wasPressed[j] = _isPressed[j];
				short state = Win32API.GetAsyncKeyState(i);

				if (!_wasPressed[j] && state != 0) {
					_isPressed[j] = true;
					KeyPressed(i);
				}else if (_isPressed[j] && state == 0) {
					_isPressed[j] = false;
				}
			}

			for (int i = 0; i < _customKeys.Length; i++) {
				int pressIndex = AlphabetSize + i;
				_wasPressed[pressIndex] = _isPressed[pressIndex];
				short state = Win32API.GetAsyncKeyState(_customKeys[i]);

				if (!_wasPressed[pressIndex] && state != 0) {
					_isPressed[pressIndex] = true;
					KeyPressed(_customKeys[i]);
				}else if (_isPressed[pressIndex] && state == 0) {
					_isPressed[pressIndex] = false;
				}
			}

			for (int i = 0; i < _specialKeys.Length; i++) {
				int pressIndex = AlphabetSize + CustomKeysSize + i;
				_wasPressed[pressIndex] = _isPressed[pressIndex];
				short state = Win32API.GetAsyncKeyState(_specialKeys[i]);

				if (!_wasPressed[pressIndex] && state != 0) {
					_isPressed[pressIndex] = true;
					KeyPressed(_specialKeys[i], true);
				}else if (_isPressed[pressIndex] && state == 0) {
					_isPressed[pressIndex] = false;
				}
			}
		}

		public bool ContainsSequence(List<int> sequence) {
			if (_lastPresses.List.Count < sequence.Count)
				return false;

			for (int i = 0; i < _lastPresses.List.Count; i++) {
				if (i >= sequence.Count)
					break;

				int keyPressed = _lastPresses.List[_lastPresses.List.Count - 1 - i];
				int sequenceKey = sequence[sequence.Count - 1 - i];

				if (keyPressed != sequenceKey) {
					return false;
				}
			}

			_lastPresses.List.Clear();
			_lastPressesWithSpecial.List.Clear();
			return true;
		}

		public bool ContainsSequence(List<int> sequence, int beginning, bool mustAppear) {
			if (_lastPressesWithSpecial.List.Count < sequence.Count + 1) {
				if (mustAppear)
					return false;
			} else {
				if (_lastPressesWithSpecial.List[^(sequence.Count + 1)] != beginning && mustAppear)
					return false;
				if (_lastPressesWithSpecial.List[^(sequence.Count + 1)] == beginning && !mustAppear)
					return false;
			}

			return ContainsSequence(sequence);
		}
	}
}