using Moq;
using PersonalToolBox.Helpers;
using PersonalToolBox.Models;
using PersonalToolBox.Services;

namespace PersonalToolBox.Tests.Helpers;

public class HotKeyManagerTests
{
    [Fact]
    public void TryParseHotKey_ValidCtrlAltT_ReturnsCorrectModifiersAndVk()
    {
        var result = HotKeyManager.TryParseHotKey("Ctrl+Alt+T", out uint mod, out uint vk);

        Assert.True(result);
        Assert.NotEqual(0u, mod);
        // 'T' → VK = 0x54
        Assert.Equal((uint)'T', vk);
    }

    [Fact]
    public void TryParseHotKey_ValidCtrlShiftF1_ReturnsCorrectVk()
    {
        var result = HotKeyManager.TryParseHotKey("Ctrl+Shift+F1", out uint mod, out uint vk);

        Assert.True(result);
        Assert.NotEqual(0u, mod);
        // F1 → VK_F1 = 0x70
        Assert.Equal(0x70u, vk);
    }

    [Fact]
    public void TryParseHotKey_OnlyModifier_ReturnsFalse()
    {
        var result = HotKeyManager.TryParseHotKey("Ctrl", out _, out _);

        Assert.False(result);
    }

    [Fact]
    public void TryParseHotKey_OnlyKey_ReturnsFalse()
    {
        var result = HotKeyManager.TryParseHotKey("T", out _, out _);

        Assert.False(result);
    }

    [Fact]
    public void TryParseHotKey_Empty_ReturnsFalse()
    {
        var result = HotKeyManager.TryParseHotKey("", out _, out _);
        Assert.False(result);
    }

    [Fact]
    public void TryParseHotKey_Null_ReturnsFalse()
    {
        var result = HotKeyManager.TryParseHotKey(null!, out _, out _);
        Assert.False(result);
    }

    [Fact]
    public void TryParseHotKey_Whitespace_ReturnsFalse()
    {
        var result = HotKeyManager.TryParseHotKey("   ", out _, out _);
        Assert.False(result);
    }

    [Fact]
    public void TryParseHotKey_WinKey_B_ReturnsCorrectVk()
    {
        var result = HotKeyManager.TryParseHotKey("Win+B", out uint mod, out uint vk);

        Assert.True(result);
        Assert.Equal((uint)'B', vk);
    }

    [Fact]
    public void TryParseHotKey_UnknownModifier_ReturnsFalse()
    {
        var result = HotKeyManager.TryParseHotKey("Foo+T", out _, out _);

        Assert.False(result);
    }

    [Fact]
    public void RegisterAll_SkipsEmptyHotKeys()
    {
        var logMock = new Mock<ILogService>();
        var processMock = new Mock<IProcessExecutionService>();
        var manager = new HotKeyManager(logMock.Object, processMock.Object);

        var tools = new[]
        {
            new ToolItem { Name = "NoHotkey", HotKey = "" },
            new ToolItem { Name = "BlankHotkey", HotKey = "   " }
        };

        // Should not throw
        manager.RegisterAll(tools);
    }

    [Fact]
    public void RegisterAll_InvalidFormat_LogsWarning()
    {
        var logMock = new Mock<ILogService>();
        var processMock = new Mock<IProcessExecutionService>();
        var manager = new HotKeyManager(logMock.Object, processMock.Object);

        // Initialize needs a hwnd, but RegisterAll calls Register which checks _hwnd
        // So calling RegisterAll without Initialize should be a no-op
        var tools = new[]
        {
            new ToolItem { Name = "Bad", HotKey = "not-a-valid-key" }
        };

        // hwnd is IntPtr.Zero, so should skip silently
        manager.RegisterAll(tools);

        // hwnd is zero, so Register is skipped entirely
        logMock.Verify(x => x.Warning(It.IsAny<string>()), Times.Never);
    }

    [Fact]
    public void TryHandleMessage_NonWMHOTKEY_ReturnsFalse()
    {
        var logMock = new Mock<ILogService>();
        var processMock = new Mock<IProcessExecutionService>();
        var manager = new HotKeyManager(logMock.Object, processMock.Object);

        var handled = manager.TryHandleMessage(9999, IntPtr.Zero, IntPtr.Zero);

        Assert.False(handled);
    }
}
