using Moq;
using Microsoft.Extensions.DependencyInjection;
using PersonalToolBox.Helpers;
using PersonalToolBox.Models;
using PersonalToolBox.Services;
using PersonalToolBox.ViewModels;

namespace PersonalToolBox.Tests.ViewModels;

public class MainViewModelTests
{
    private readonly Mock<ILogService> _logServiceMock = new();
    private readonly Mock<IDataService> _dataServiceMock = new();
    private readonly Mock<IProcessExecutionService> _processServiceMock = new();
    private readonly Mock<IServiceProvider> _serviceProviderMock = new();
    private readonly Mock<HotKeyManager> _hotKeyManagerMock;
    private readonly AppConfig _config;

    public MainViewModelTests()
    {
        _config = new AppConfig
        {
            Theme = "Dark",
            Categories =
            [
                new() { Id = "1", Name = "开发工具" },
                new() { Id = "2", Name = "系统工具" }
            ],
            Tools =
            [
                new() { Id = "t1", Name = "VS Code", CategoryId = "1", IsValid = true },
                new() { Id = "t2", Name = "Postman", CategoryId = "1", IsValid = true },
                new() { Id = "t3", Name = "任务管理器", CategoryId = "2", IsValid = true },
                new() { Id = "t4", Name = "失效工具", CategoryId = "1", ExecutablePath = @"C:\missing.exe", IsValid = false }
            ]
        };

        _hotKeyManagerMock = new Mock<HotKeyManager>(_logServiceMock.Object, _processServiceMock.Object);
        _dataServiceMock.Setup(d => d.Config).Returns(_config);
    }

    private MainViewModel CreateViewModel() =>
        new(_logServiceMock.Object, _dataServiceMock.Object, _processServiceMock.Object,
            _serviceProviderMock.Object, _hotKeyManagerMock.Object);

    [Fact]
    public void Constructor_LoadsCategories_IncludingAll()
    {
        var vm = CreateViewModel();

        Assert.Equal(3, vm.Categories.Count);
        Assert.Equal("全部", vm.Categories[0].Name);
        Assert.Equal("开发工具", vm.Categories[1].Name);
        Assert.Equal("系统工具", vm.Categories[2].Name);
    }

    [Fact]
    public void Constructor_LoadsAllTools()
    {
        var vm = CreateViewModel();
        Assert.Equal(4, vm.Tools.Count);
    }

    [Fact]
    public void Default_CategoryIsAll_ShowsAllTools()
    {
        var vm = CreateViewModel();
        Assert.Equal(4, vm.FilteredTools.Count);
    }

    [Fact]
    public void SelectCategory_FiltersByCategory()
    {
        var vm = CreateViewModel();
        vm.SelectedCategory = vm.Categories[1];
        Assert.Equal(3, vm.FilteredTools.Count);
    }

    [Fact]
    public void SearchText_FiltersByName()
    {
        var vm = CreateViewModel();
        vm.SearchText = "post";
        Assert.Single(vm.FilteredTools);
        Assert.Equal("Postman", vm.FilteredTools[0].Name);
    }

    [Fact]
    public void SearchText_CaseInsensitive()
    {
        var vm = CreateViewModel();
        vm.SearchText = "POSTMAN";
        Assert.Single(vm.FilteredTools);
        Assert.Equal("Postman", vm.FilteredTools[0].Name);
    }

    [Fact]
    public void SearchText_And_Category_FilterCombined()
    {
        var vm = CreateViewModel();
        vm.SelectedCategory = vm.Categories[1];
        vm.SearchText = "code";
        Assert.Single(vm.FilteredTools);
        Assert.Equal("VS Code", vm.FilteredTools[0].Name);
    }

    [Fact]
    public void SearchText_Empty_ShowsAllInCategory()
    {
        var vm = CreateViewModel();
        vm.SelectedCategory = vm.Categories[2];
        vm.SearchText = "";
        Assert.Single(vm.FilteredTools);
        Assert.Equal("任务管理器", vm.FilteredTools[0].Name);
    }

    [Fact]
    public void SearchText_NoMatch_ReturnsEmpty()
    {
        var vm = CreateViewModel();
        vm.SearchText = "nonexistent";
        Assert.Empty(vm.FilteredTools);
    }

    [Fact]
    public void InvalidTools_StillAppearInFilteredResults()
    {
        var vm = CreateViewModel();
        vm.SelectedCategory = vm.Categories[1];
        var invalid = vm.FilteredTools.FirstOrDefault(t => t.Name == "失效工具");
        Assert.NotNull(invalid);
        Assert.False(invalid.IsValid);
    }

    [Fact]
    public void ClearLogsCommand_CallsLogServiceClear()
    {
        var vm = CreateViewModel();
        vm.ClearLogsCommand.Execute(null);
        _logServiceMock.Verify(x => x.Clear(), Times.Once);
    }

    [Fact]
    public void ToggleTheme_SwitchesDarkToLight()
    {
        var vm = CreateViewModel();
        Assert.Equal("Dark", vm.CurrentTheme);
        vm.ToggleThemeCommand.Execute(null);
        Assert.Equal("Light", vm.CurrentTheme);
    }

    [Fact]
    public void ToggleTheme_CallsSave()
    {
        var vm = CreateViewModel();
        vm.ToggleThemeCommand.Execute(null);
        _dataServiceMock.Verify(x => x.Save(), Times.Once);
    }

    [Fact]
    public void ExecuteTool_CallsProcessService()
    {
        var vm = CreateViewModel();
        var tool = vm.Tools[0];

        vm.ExecuteToolCommand.Execute(tool);

        _processServiceMock.Verify(x => x.ExecuteAsync(tool), Times.Once);
    }

    [Fact]
    public void ExecuteTool_Null_DoesNotCallProcessService()
    {
        var vm = CreateViewModel();
        vm.ExecuteToolCommand.Execute(null);
        _processServiceMock.Verify(x => x.ExecuteAsync(It.IsAny<ToolItem>()), Times.Never);
    }

    [Fact]
    public void RefreshData_ReloadsFromConfig()
    {
        var vm = CreateViewModel();

        _config.Tools.Add(new ToolItem { Name = "NewTool" });

        vm.RefreshData();

        Assert.Equal(5, vm.Tools.Count);
    }
}
