using VisionBuilder.UI.Common.ViewModel;
using VisionBuilder.UI.Common.ViewModel.Classes;
using VisionBuilder.UI.Common.ViewModel.Interfaces.UI;

namespace VisionBuilder.UI.Tests;

[TestClass]
public sealed class DynamicButtonTests
{
    private class StubSettingsService : ISettingsService
    {
        public Task ShowSettingsDialogAsync() => Task.CompletedTask;
    }

    #region ButtonDefinition Tests

    [TestMethod]
    public void ClickButton_Execute_InvokesCallback()
    {
        bool called = false;
        var button = new ButtonDefinition("key1", "Test", () => called = true);

        button.Execute();

        Assert.IsTrue(called);
    }

    [TestMethod]
    public void ClickButton_HasCorrectProperties()
    {
        var button = new ButtonDefinition("myKey", "My Title", () => { });

        Assert.AreEqual("myKey", button.Key);
        Assert.AreEqual("My Title", button.Title);
        Assert.AreEqual(EButtonType.Click, button.Type);
    }

    [TestMethod]
    public void ToggleButton_Execute_TogglesAndInvokesCallback()
    {
        bool? receivedState = null;
        var button = new ButtonDefinition("key1", "Test", (state) => receivedState = state);

        button.Execute();

        Assert.IsTrue(button.IsToggled);
        Assert.AreEqual(true, receivedState);
    }

    [TestMethod]
    public void ToggleButton_ExecuteTwice_TogglesBack()
    {
        bool? receivedState = null;
        var button = new ButtonDefinition("key1", "Test", (state) => receivedState = state);

        button.Execute();
        button.Execute();

        Assert.IsFalse(button.IsToggled);
        Assert.AreEqual(false, receivedState);
    }

    [TestMethod]
    public void ToggleButton_InitialState_IsRespected()
    {
        var button = new ButtonDefinition("key1", "Test", (_) => { }, initialState: true);

        Assert.IsTrue(button.IsToggled);
        Assert.AreEqual(EButtonType.Toggle, button.Type);
    }

    [TestMethod]
    public void ButtonDefinition_IsVisible_DefaultTrue()
    {
        var button = new ButtonDefinition("key1", "Test", () => { });

        Assert.IsTrue(button.IsVisible);
    }

    [TestMethod]
    public void ButtonDefinition_SetVisibility_RaisesPropertyChanged()
    {
        var button = new ButtonDefinition("key1", "Test", () => { });
        string? changedProperty = null;
        button.PropertyChanged += (_, args) => changedProperty = args.PropertyName;

        button.IsVisible = false;

        Assert.AreEqual(nameof(ButtonDefinition.IsVisible), changedProperty);
        Assert.IsFalse(button.IsVisible);
    }

    [TestMethod]
    public void ToggleButton_Execute_RaisesToggledPropertyChanged()
    {
        var button = new ButtonDefinition("key1", "Test", (_) => { });
        string? changedProperty = null;
        button.PropertyChanged += (_, args) => changedProperty = args.PropertyName;

        button.Execute();

        Assert.AreEqual(nameof(ButtonDefinition.IsToggled), changedProperty);
    }

    #endregion

    #region MainWindowVM Tests

    [TestMethod]
    public void MainWindowVM_AddButton_AddsToCollection()
    {
        var vm = new MainWindowVM(new StubSettingsService());
        var button = new ButtonDefinition("key1", "Test", () => { });

        vm.AddButton(button);

        Assert.AreEqual(1, vm.DynamicButtons.Count);
        Assert.AreSame(button, vm.DynamicButtons[0]);
    }

    [TestMethod]
    public void MainWindowVM_SetButtonVisibility_UpdatesButton()
    {
        var vm = new MainWindowVM(new StubSettingsService());
        var button = new ButtonDefinition("key1", "Test", () => { });
        vm.AddButton(button);

        vm.SetButtonVisibility("key1", false);

        Assert.IsFalse(button.IsVisible);
    }

    [TestMethod]
    public void MainWindowVM_SetButtonVisibility_NonExistentKey_DoesNothing()
    {
        var vm = new MainWindowVM(new StubSettingsService());
        var button = new ButtonDefinition("key1", "Test", () => { });
        vm.AddButton(button);

        vm.SetButtonVisibility("nonexistent", false);

        Assert.IsTrue(button.IsVisible);
    }

    [TestMethod]
    public void MainWindowVM_RemoveButton_RemovesFromCollection()
    {
        var vm = new MainWindowVM(new StubSettingsService());
        var button = new ButtonDefinition("key1", "Test", () => { });
        vm.AddButton(button);

        vm.RemoveButton("key1");

        Assert.AreEqual(0, vm.DynamicButtons.Count);
    }

    [TestMethod]
    public void MainWindowVM_RemoveButton_NonExistentKey_DoesNothing()
    {
        var vm = new MainWindowVM(new StubSettingsService());
        var button = new ButtonDefinition("key1", "Test", () => { });
        vm.AddButton(button);

        vm.RemoveButton("nonexistent");

        Assert.AreEqual(1, vm.DynamicButtons.Count);
    }

    #endregion
}
