using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Decal.Interop.Input;

namespace Decal.DecalInput
{
    [ComVisible(true)]
    [Guid("F183506A-3664-49D6-8CA4-CFD295F2811D")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(IHotkeyEvents))]
    [ProgId("DecalInput.Hotkey")]
    public class HotkeyImpl : IHotkey
    {
        private object _tag;
        private int _vk = -1;
        private bool _enabled;

        public event IHotkeyEvents_HotkeyEventHandler Hotkey;

        public object Tag
        {
            get => _tag;
            set => _tag = value;
        }

        public string Key
        {
            get
            {
                if (_vk == -1) return string.Empty;
                string name = KeyNames.NameFromVK(_vk);
                return name != null ? "{" + name + "}" : ((char)_vk).ToString();
            }
            set
            {
                string s = value?.ToUpperInvariant();
                if (string.IsNullOrEmpty(s)) return;

                if (s[0] == '{')
                {
                    int end = s.IndexOf('}');
                    if (end > 1)
                    {
                        string keyName = s.Substring(1, end - 1);
                        int vk = KeyNames.VKFromName(keyName);
                        if (vk >= 0) _vk = vk;
                    }
                }
                else if (s.Length == 1)
                {
                    _vk = s[0];
                }
            }
        }

        public bool Enabled
        {
            get => _enabled;
            set
            {
                if (value == _enabled) return;
                _enabled = value;

                if (InputServiceImpl.Instance != null)
                {
                    if (_enabled)
                        InputServiceImpl.Instance.RegisterHotkey(this);
                    else
                        InputServiceImpl.Instance.UnregisterHotkey(this);
                }
            }
        }

        internal void FireHotkey()
        {
            Hotkey?.Invoke((Hotkey)(object)this);
        }
    }

    internal static class KeyNames
    {
        private static readonly Dictionary<string, int> _nameToVK = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
        {
            {"BACKSPACE", 0x08}, {"BS", 0x08}, {"BKSP", 0x08},
            {"CAPSLOCK", 0x14}, {"DELETE", 0x2E}, {"DEL", 0x2E},
            {"DOWN", 0x28}, {"END", 0x23}, {"ENTER", 0x0D},
            {"ESC", 0x1B}, {"HELP", 0x2F}, {"HOME", 0x24},
            {"INS", 0x2D}, {"INSERT", 0x2D}, {"LEFT", 0x25},
            {"NUMLOCK", 0x90}, {"PGDN", 0x22}, {"PGUP", 0x21},
            {"PRTSC", 0x2C}, {"RIGHT", 0x27}, {"SCROLLLOCK", 0x91},
            {"TAB", 0x09}, {"UP", 0x26},
            {"F1", 0x70}, {"F2", 0x71}, {"F3", 0x72}, {"F4", 0x73},
            {"F5", 0x74}, {"F6", 0x75}, {"F7", 0x76}, {"F8", 0x77},
            {"F9", 0x78}, {"F10", 0x79}, {"F11", 0x7A}, {"F12", 0x7B},
            {"F13", 0x7C}, {"F14", 0x7D}, {"F15", 0x7E}, {"F16", 0x7F},
            {"+", 0x6B}, {"SHIFT", 0x10}, {"CTRL", 0x11}, {"ALT", 0x12},
            {"LBUTTON", 0x01}, {"RBUTTON", 0x02}
        };

        private static readonly Dictionary<int, string> _vkToName;

        static KeyNames()
        {
            _vkToName = new Dictionary<int, string>();
            // Build reverse mapping, preferring longer names
            foreach (var kvp in _nameToVK)
            {
                if (!_vkToName.ContainsKey(kvp.Value) || kvp.Key.Length > _vkToName[kvp.Value].Length)
                    _vkToName[kvp.Value] = kvp.Key;
            }
        }

        public static int VKFromName(string name) =>
            _nameToVK.TryGetValue(name, out int vk) ? vk : -1;

        public static string NameFromVK(int vk) =>
            _vkToName.TryGetValue(vk, out string name) ? name : null;
    }
}
