using System.Text.Json;
using FluentAssertions;
using AxCopilot.Models;
using Xunit;

namespace AxCopilot.Tests.Services;

public class SettingsServiceTests
{
    // ─── AppSettings 기본값 ──────────────────────────────────────────────────

    [Fact]
    public void AppSettings_DefaultHotkey_IsAltSpace()
    {
        new AppSettings().Hotkey.Should().Be("Alt+Space");
    }

    [Fact]
    public void LauncherSettings_DefaultMaxResults_IsSeven()
    {
        new LauncherSettings().MaxResults.Should().Be(7);
    }

    [Fact]
    public void LauncherSettings_DefaultTheme_IsSystem()
    {
        new LauncherSettings().Theme.Should().Be("system");
    }

    [Fact]
    public void LauncherSettings_DefaultOpacity_IsValid()
    {
        var opacity = new LauncherSettings().Opacity;
        opacity.Should().BeInRange(0.0, 1.0);
    }

    [Fact]
    public void AppSettings_DefaultMonitorMismatch_IsWarn()
    {
        new AppSettings().MonitorMismatch.Should().Be("warn");
    }

    [Fact]
    public void AppSettings_DefaultIndexPaths_NotEmpty()
    {
        new AppSettings().IndexPaths.Should().NotBeEmpty();
    }

    // ─── LauncherSettings 테마 ───────────────────────────────────────────────

    [Theory]
    [InlineData("system")]
    [InlineData("dark")]
    [InlineData("light")]
    public void LauncherSettings_Theme_AcceptsValidValues(string theme)
    {
        var settings = new LauncherSettings { Theme = theme };
        settings.Theme.Should().Be(theme);
    }

    // ─── JSON 직렬화 라운드트립 ──────────────────────────────────────────────

    [Fact]
    public void AppSettings_Serialization_PreservesHotkey()
    {
        var original = new AppSettings { Hotkey = "Ctrl+Space" };
        var restored = RoundTrip(original);
        restored.Hotkey.Should().Be("Ctrl+Space");
    }

    [Fact]
    public void AppSettings_Serialization_PreservesTheme()
    {
        var original = new AppSettings
        {
            Launcher = new LauncherSettings { Theme = "dark" }
        };
        var restored = RoundTrip(original);
        restored.Launcher.Theme.Should().Be("dark");
    }

    [Fact]
    public void AppSettings_Serialization_PreservesMaxResults()
    {
        var original = new AppSettings
        {
            Launcher = new LauncherSettings { MaxResults = 15 }
        };
        var restored = RoundTrip(original);
        restored.Launcher.MaxResults.Should().Be(15);
    }

    [Fact]
    public void AppSettings_Serialization_PreservesAliases()
    {
        var original = new AppSettings
        {
            Aliases =
            [
                new() { Key = "@test", Type = "url", Target = "https://example.com" }
            ]
        };
        var restored = RoundTrip(original);
        restored.Aliases.Should().HaveCount(1);
        restored.Aliases[0].Key.Should().Be("@test");
        restored.Aliases[0].Target.Should().Be("https://example.com");
    }

    // ─── AliasEntry ──────────────────────────────────────────────────────────

    [Fact]
    public void AliasEntry_DefaultShowWindow_IsFalse()
    {
        new AliasEntry().ShowWindow.Should().BeFalse();
    }

    [Theory]
    [InlineData("url")]
    [InlineData("folder")]
    [InlineData("app")]
    [InlineData("batch")]
    [InlineData("api")]
    [InlineData("clipboard")]
    public void AliasEntry_Type_AcceptsAllTypes(string type)
    {
        var entry = new AliasEntry { Type = type };
        entry.Type.Should().Be(type);
    }

    // ─── WorkspaceProfile / WindowSnapshot ───────────────────────────────────

    [Fact]
    public void WorkspaceProfile_DefaultWindows_IsEmpty()
    {
        new WorkspaceProfile().Windows.Should().BeEmpty();
    }

    [Fact]
    public void WindowSnapshot_DefaultShowCmd_IsNormal()
    {
        new WindowSnapshot().ShowCmd.Should().Be("Normal");
    }

    [Fact]
    public void WindowSnapshot_DefaultMonitor_IsZero()
    {
        new WindowSnapshot().Monitor.Should().Be(0);
    }

    [Fact]
    public void WindowRect_DefaultValues_AreZero()
    {
        var rect = new WindowRect();
        rect.X.Should().Be(0);
        rect.Y.Should().Be(0);
        rect.Width.Should().Be(0);
        rect.Height.Should().Be(0);
    }

    [Fact]
    public void WorkspaceProfile_Serialization_RoundTrip()
    {
        var profile = new WorkspaceProfile
        {
            Name = "작업 프로필",
            Windows =
            [
                new() { Exe = "notepad.exe", ShowCmd = "Maximized", Monitor = 1 }
            ]
        };
        var json = JsonSerializer.Serialize(profile, JsonOptions);
        var restored = JsonSerializer.Deserialize<WorkspaceProfile>(json, JsonOptions)!;

        restored.Name.Should().Be("작업 프로필");
        restored.Windows.Should().HaveCount(1);
        restored.Windows[0].Exe.Should().Be("notepad.exe");
        restored.Windows[0].ShowCmd.Should().Be("Maximized");
        restored.Windows[0].Monitor.Should().Be(1);
    }

    // ─── ClipboardTransformer ────────────────────────────────────────────────

    [Fact]
    public void ClipboardTransformer_DefaultTimeout_IsFiveSeconds()
    {
        new ClipboardTransformer().Timeout.Should().Be(5000);
    }

    [Fact]
    public void ClipboardTransformer_DefaultType_IsRegex()
    {
        new ClipboardTransformer().Type.Should().Be("regex");
    }

    // ─── Helpers ─────────────────────────────────────────────────────────────

    private static readonly JsonSerializerOptions JsonOptions = new()
    {
        WriteIndented = false,
        PropertyNameCaseInsensitive = true
    };

    private static AppSettings RoundTrip(AppSettings original)
    {
        var json = JsonSerializer.Serialize(original, JsonOptions);
        return JsonSerializer.Deserialize<AppSettings>(json, JsonOptions)!;
    }
}
