using AppClientBase.Services;
using AppClientBase.ViewModels;
using FluentAssertions;
using Xunit;

namespace AppClientBase.UnitTests.ViewModels;

/// <summary>
/// EN: Unit tests for main view model behavior.
/// VI: Unit tests cho hành vi của main view model.
/// </summary>
public class MainViewModelTests
{
    [Fact]
    public void Constructor_ShouldSetDefaultTitleAndWelcomeMessage()
    {
        // Arrange
        var navigationService = new FakeNavigationService();
        var settingsService = new FakeSettingsService();

        // Act
        var viewModel = new MainViewModel(navigationService, settingsService);

        // Assert
        viewModel.Title.Should().Be("Home");
        viewModel.WelcomeMessage.Should().Be("Welcome to AppClientBase!");
        viewModel.ClickCount.Should().Be(0);
        viewModel.ButtonText.Should().Be("Click me");
    }

    [Fact]
    public void IncrementCounterCommand_ShouldIncreaseCountAndPersistSetting()
    {
        // Arrange
        var navigationService = new FakeNavigationService();
        var settingsService = new FakeSettingsService();
        var viewModel = new MainViewModel(navigationService, settingsService);

        // Act
        viewModel.IncrementCounterCommand.Execute(null);
        viewModel.IncrementCounterCommand.Execute(null);

        // Assert
        viewModel.ClickCount.Should().Be(2);
        viewModel.ButtonText.Should().Be("Clicked 2 times");
        settingsService.Get("ClickCount", 0).Should().Be(2);
    }

    private sealed class FakeNavigationService : INavigationService
    {
        public Task GoToAsync(string route, IDictionary<string, object>? parameters = null) => Task.CompletedTask;

        public Task GoBackAsync() => Task.CompletedTask;
    }

    private sealed class FakeSettingsService : ISettingsService
    {
        private readonly Dictionary<string, object?> _store = new(StringComparer.Ordinal);

        public T Get<T>(string key, T defaultValue)
        {
            if (_store.TryGetValue(key, out var value) && value is T typed)
            {
                return typed;
            }

            return defaultValue;
        }

        public void Set<T>(string key, T value)
        {
            _store[key] = value;
        }

        public bool Contains(string key) => _store.ContainsKey(key);

        public void Remove(string key) => _store.Remove(key);

        public void Clear() => _store.Clear();
    }
}
