using System;
using System.Runtime.InteropServices;
using System.Windows.Input;
using System.Windows.Interop;

namespace TodoList.Services
{
    public class GlobalShortcutService : IDisposable
    {
        private const int HOTKEY_ID = 9000;

        public const uint MOD_ALT = 0x0001;
        public const uint MOD_CONTROL = 0x0002;
        public const uint MOD_SHIFT = 0x0004;
        public const uint MOD_WIN = 0x0008;

        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        private IntPtr _windowHandle;
        private HwndSource _source;
        private Action _onHotKeyPressed;
        private bool _isRegistered;

        public void Register(IntPtr windowHandle, Action onHotKeyPressed, uint modifiers, uint key)
        {
            // If already registered, unregister first (to support updating)
            if (_isRegistered)
            {
                UnregisterHotKey(_windowHandle, HOTKEY_ID);
                _source?.RemoveHook(HwndHook);
                _isRegistered = false;
            }

            _windowHandle = windowHandle;
            _onHotKeyPressed = onHotKeyPressed;

            _source = HwndSource.FromHwnd(_windowHandle);
            if (_source == null) return; // Should not happen if handle is valid
            
            _source.AddHook(HwndHook);

            if (RegisterHotKey(_windowHandle, HOTKEY_ID, modifiers, key))
            {
                _isRegistered = true;
            }
            else
            {
                System.Diagnostics.Debug.WriteLine("Failed to register hotkey.");
            }
        }

        public void UpdateShortcut(uint modifiers, uint key)
        {
            if (_windowHandle != IntPtr.Zero && _onHotKeyPressed != null)
            {
                // Re-register with new keys
                Register(_windowHandle, _onHotKeyPressed, modifiers, key);
            }
        }

        private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            const int WM_HOTKEY = 0x0312;
            if (msg == WM_HOTKEY)
            {
                if (wParam.ToInt32() == HOTKEY_ID)
                {
                    _onHotKeyPressed?.Invoke();
                    handled = true;
                }
            }
            return IntPtr.Zero;
        }

        public void Unregister()
        {
            if (_isRegistered)
            {
                _source?.RemoveHook(HwndHook);
                UnregisterHotKey(_windowHandle, HOTKEY_ID);
                _isRegistered = false;
            }
        }

        public void Dispose()
        {
            Unregister();
        }

        public static uint GetModifier(string modifiers)
        {
            uint mod = 0;
            if (string.IsNullOrEmpty(modifiers)) return mod;

            var parts = modifiers.Split(',');
            foreach (var part in parts)
            {
                var p = part.Trim();
                if (p.Equals("Control", StringComparison.OrdinalIgnoreCase)) mod |= MOD_CONTROL;
                if (p.Equals("Alt", StringComparison.OrdinalIgnoreCase)) mod |= MOD_ALT;
                if (p.Equals("Shift", StringComparison.OrdinalIgnoreCase)) mod |= MOD_SHIFT;
                if (p.Equals("Windows", StringComparison.OrdinalIgnoreCase)) mod |= MOD_WIN;
            }
            return mod;
        }

        public static uint GetKey(string key)
        {
            if (Enum.TryParse<Key>(key, out var k))
            {
                return (uint)KeyInterop.VirtualKeyFromKey(k);
            }
            // Fallback for simple letters if Key enum doesn't match directly (though it should for A-Z)
             if (key.Length == 1)
            {
                char c = char.ToUpper(key[0]);
                if (c >= 'A' && c <= 'Z') return (uint)c;
                if (c >= '0' && c <= '9') return (uint)c;
            }
            return 0x41; // Default 'A'
        }
    }
}
