using Moq;
using PersonalToolBox.Models;
using PersonalToolBox.Services;
using PersonalToolBox.ViewModels;

namespace PersonalToolBox.Tests.ViewModels;

public class ToolEditViewModelTests
{
    private readonly Mock<IDataService> _dataServiceMock = new();
    private readonly Mock<ILogService> _logServiceMock = new();
    private readonly AppConfig _config;

    public ToolEditViewModelTests()
    {
        _config = new AppConfig
        {
            Categories =
            [
                new() { Id = "1", Name = "开发工具" }
            ]
        };
        _dataServiceMock.Setup(d => d.Config).Returns(_config);
    }

    [Fact]
    public void Constructor_AddMode_SetsTitle()
    {
        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object);

        Assert.Equal("添加工具", vm.WindowTitle);
        Assert.Empty(vm.Name);
        Assert.Empty(vm.ExecutablePath);
    }

    [Fact]
    public void Constructor_EditMode_SetsTitleAndFields()
    {
        var tool = new ToolItem
        {
            Name = "MyTool",
            ExecutablePath = @"C:\test.exe",
            Arguments = "/arg",
            HotKey = "Ctrl+T",
            CategoryId = "1"
        };

        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object, tool);

        Assert.Equal("编辑工具", vm.WindowTitle);
        Assert.Equal("MyTool", vm.Name);
        Assert.Equal(@"C:\test.exe", vm.ExecutablePath);
        Assert.Equal("/arg", vm.Arguments);
        Assert.Equal("Ctrl+T", vm.HotKey);
    }

    [Fact]
    public void Save_EmptyName_LogsWarning()
    {
        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object)
        {
            ExecutablePath = @"C:\test.exe"
        };

        vm.SaveCommand.Execute(null);

        _logServiceMock.Verify(x => x.Warning(It.Is<string>(s => s.Contains("名称不能为空"))), Times.Once);
    }

    [Fact]
    public void Save_EmptyPath_LogsWarning()
    {
        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object)
        {
            Name = "Test"
        };

        vm.SaveCommand.Execute(null);

        _logServiceMock.Verify(x => x.Warning(It.Is<string>(s => s.Contains("路径不能为空"))), Times.Once);
    }

    [Fact]
    public void Save_AddMode_AddsToolAndCloses()
    {
        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object)
        {
            Name = "NewTool",
            ExecutablePath = @"C:\test.exe"
        };
        bool? closeResult = null;
        vm.CloseAction = (r) => closeResult = r;

        vm.SaveCommand.Execute(null);

        Assert.True(vm.Saved);
        Assert.True(closeResult);
        Assert.Single(_config.Tools);
        Assert.Equal("NewTool", _config.Tools[0].Name);
        _dataServiceMock.Verify(x => x.Save(), Times.Once);
    }

    [Fact]
    public void Save_EditMode_UpdatesToolAndCloses()
    {
        var tool = new ToolItem
        {
            Name = "OldName",
            ExecutablePath = @"C:\old.exe"
        };

        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object, tool)
        {
            Name = "NewName",
            ExecutablePath = @"C:\new.exe"
        };
        bool? closeResult = null;
        vm.CloseAction = (r) => closeResult = r;

        vm.SaveCommand.Execute(null);

        Assert.True(vm.Saved);
        Assert.True(closeResult);
        Assert.Equal("NewName", tool.Name);
        Assert.Equal(@"C:\new.exe", tool.ExecutablePath);
        _dataServiceMock.Verify(x => x.Save(), Times.Once);
    }

    [Fact]
    public void Cancel_ClosesWithoutSaving()
    {
        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object);
        bool? closeResult = null;
        vm.CloseAction = (r) => closeResult = r;

        vm.CancelCommand.Execute(null);

        Assert.False(vm.Saved);
        Assert.False(closeResult);
        _dataServiceMock.Verify(x => x.Save(), Times.Never);
    }

    [Fact]
    public void Constructor_LoadsCategories()
    {
        var vm = new ToolEditViewModel(_dataServiceMock.Object, _logServiceMock.Object);

        Assert.Single(vm.Categories);
        Assert.Equal("开发工具", vm.Categories[0].Name);
    }
}
