using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using KeyEventHandler = System.Windows.Input.KeyEventHandler;

namespace InABox.WPF
{
    public enum HotKeyModifier
    {
        Ctrl,
        Shift,
        Alt
    }

    public static class HotKeyManager
    {
        private static readonly List<Tuple<Key, HotKeyModifier[], Func<bool>>> _hotkeys = new();

        private static Tuple<Key, HotKeyModifier[], Func<bool>> FindHotKey(Key key, HotKeyModifier[] modifiers)
        {
            var m = modifiers != null ? modifiers : new HotKeyModifier[] { };
            var existing = _hotkeys.FirstOrDefault(
                x => x.Item1 == key && x.Item2.Length == m.Length && x.Item2.Intersect(m).Count() == x.Item2.Length);
            return existing;
        }

        public static void RegisterHotKey(Key key, Func<bool> action)
        {
            RegisterHotKey(key, new HotKeyModifier[] { }, action);
        }

        public static void RegisterHotKey(Key key, HotKeyModifier[] modifiers, Func<bool> action)
        {
            var existing = FindHotKey(key, modifiers);
            if (existing != null)
                throw new Exception(string.Format("HotKey [{0}+{1}] is already registered!", string.Join("+", modifiers.Select(x => x)), key));
            _hotkeys.Add(new Tuple<Key, HotKeyModifier[], Func<bool>>(key, modifiers, action));
        }

        public static void UnRegisterHotKey(Key key)
        {
            UnRegisterHotKey(key, new HotKeyModifier[] { });
        }

        public static void UnRegisterHotKey(Key key, HotKeyModifier[] modifiers)
        {
            var existing = FindHotKey(key, modifiers);
            if (existing != null)
                _hotkeys.Remove(existing);
        }

        public static bool ProcessHotKey(Key key)
        {
            var modifiers = new List<HotKeyModifier>();
            if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
                modifiers.Add(HotKeyModifier.Shift);
            if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                modifiers.Add(HotKeyModifier.Ctrl);
            if (Keyboard.IsKeyDown(Key.LeftAlt) || Keyboard.IsKeyDown(Key.RightAlt))
                modifiers.Add(HotKeyModifier.Alt);

            var existing = FindHotKey(key, modifiers.ToArray());
            if (existing != null)
                return existing.Item3.Invoke();
            return false;
        }

        public static void Initialize()
        {
            EventManager.RegisterClassHandler(
                typeof(Window),
                Keyboard.KeyDownEvent,
                new KeyEventHandler(
                    (o, args) =>
                    {
                        ProcessHotKey(args.Key);
                        //args.Handled = args.Key == Key.Space ? true : ProcessHotKey(args.Key);
                    }
                ),
                true
            );
        }
    }
}