using System.Text;
using FluentAssertions;
using AxCopilot.Handlers;
using Xunit;

namespace AxCopilot.Tests.Handlers;

public class ClipboardTransformTests
{
    // ─── 대소문자 변환 ────────────────────────────────────────────────────────

    [Fact]
    public void Upper_ConvertsToUppercase()
    {
        ClipboardHandler.ExecuteBuiltin("$upper", "hello world").Should().Be("HELLO WORLD");
    }

    [Fact]
    public void Lower_ConvertsToLowercase()
    {
        ClipboardHandler.ExecuteBuiltin("$lower", "HELLO WORLD").Should().Be("hello world");
    }

    // ─── Base64 ──────────────────────────────────────────────────────────────

    [Fact]
    public void Base64Encode_EncodesCorrectly()
    {
        ClipboardHandler.ExecuteBuiltin("$b64e", "hello").Should().Be("aGVsbG8=");
    }

    [Fact]
    public void Base64Decode_DecodesCorrectly()
    {
        ClipboardHandler.ExecuteBuiltin("$b64d", "aGVsbG8=").Should().Be("hello");
    }

    [Fact]
    public void Base64_RoundTrip()
    {
        var original = "AX Copilot 테스트";
        var encoded = ClipboardHandler.ExecuteBuiltin("$b64e", original)!;
        var decoded = ClipboardHandler.ExecuteBuiltin("$b64d", encoded);
        decoded.Should().Be(original);
    }

    // ─── URL 인코딩 ──────────────────────────────────────────────────────────

    [Fact]
    public void UrlEncode_EncodesSpaces()
    {
        ClipboardHandler.ExecuteBuiltin("$urle", "hello world").Should().Be("hello%20world");
    }

    [Fact]
    public void UrlDecode_DecodesSpaces()
    {
        ClipboardHandler.ExecuteBuiltin("$urld", "hello%20world").Should().Be("hello world");
    }

    [Fact]
    public void UrlEncode_EncodesSpecialChars()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$urle", "a=b&c=d");
        result.Should().Be("a%3Db%26c%3Dd");
    }

    [Fact]
    public void UrlDecode_DecodesSpecialChars()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$urld", "a%3Db%26c%3Dd");
        result.Should().Be("a=b&c=d");
    }

    // ─── 문자열 처리 ─────────────────────────────────────────────────────────

    [Fact]
    public void Trim_RemovesLeadingTrailingWhitespace()
    {
        ClipboardHandler.ExecuteBuiltin("$trim", "  hello  ").Should().Be("hello");
    }

    [Fact]
    public void Trim_PreservesInternalSpaces()
    {
        ClipboardHandler.ExecuteBuiltin("$trim", "  hello world  ").Should().Be("hello world");
    }

    [Fact]
    public void Lines_RemovesEmptyLines()
    {
        var input = "a\n\nb\n  \nc";
        var result = ClipboardHandler.ExecuteBuiltin("$lines", input);
        result.Should().NotContain("\n\n");
        result.Should().Contain("a");
        result.Should().Contain("b");
        result.Should().Contain("c");
    }

    [Fact]
    public void Lines_TrimsEachLine()
    {
        var input = "  hello  \n  world  ";
        var result = ClipboardHandler.ExecuteBuiltin("$lines", input)!;
        result.Should().Contain("hello");
        result.Should().Contain("world");
        result.Should().NotContain("  hello");
    }

    // ─── 타임스탬프 ──────────────────────────────────────────────────────────

    [Fact]
    public void Timestamp_EpochZero_Returns1970()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$ts", "0");
        result.Should().NotBeNullOrEmpty();
        result.Should().Contain("1970");
    }

    [Fact]
    public void Timestamp_ValidEpoch_ReturnsDateString()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$ts", "1700000000");
        result.Should().NotBeNullOrEmpty();
        result.Should().MatchRegex(@"\d{4}-\d{2}-\d{2}");
    }

    [Fact]
    public void Timestamp_InvalidInput_ReturnsNull()
    {
        ClipboardHandler.ExecuteBuiltin("$ts", "not-a-number").Should().BeNull();
    }

    [Fact]
    public void Epoch_ValidDate_ReturnsNumber()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$epoch", "1970-01-01");
        result.Should().NotBeNullOrEmpty();
        long.TryParse(result, out _).Should().BeTrue();
    }

    [Fact]
    public void Epoch_InvalidDate_ReturnsNull()
    {
        ClipboardHandler.ExecuteBuiltin("$epoch", "not-a-date").Should().BeNull();
    }

    // ─── JSON 포맷팅 ─────────────────────────────────────────────────────────

    [Fact]
    public void JsonFormat_MinifiedJson_AddsIndentation()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$json", "{\"a\":1,\"b\":2}");
        result.Should().NotBeNullOrEmpty();
        result.Should().Contain("\n");
        result.Should().Contain("\"a\"");
    }

    [Fact]
    public void JsonFormat_AlreadyFormatted_StaysValid()
    {
        var formatted = "{\n  \"a\": 1\n}";
        var result = ClipboardHandler.ExecuteBuiltin("$json", formatted);
        result.Should().NotBeNullOrEmpty();
        result.Should().Contain("\"a\"");
    }

    [Fact]
    public void JsonFormat_InvalidJson_ReturnsOriginal()
    {
        var invalid = "not json";
        var result = ClipboardHandler.ExecuteBuiltin("$json", invalid);
        result.Should().Be(invalid); // 파싱 실패 시 원본 반환
    }

    // ─── 마크다운 제거 ───────────────────────────────────────────────────────

    [Fact]
    public void StripMarkdown_RemovesBold()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$md", "**bold text**");
        result.Should().NotContain("**");
        result.Should().Contain("bold text");
    }

    [Fact]
    public void StripMarkdown_RemovesItalic()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$md", "*italic*");
        result.Should().NotContain("*italic*");
        result.Should().Contain("italic");
    }

    [Fact]
    public void StripMarkdown_RemovesInlineCode()
    {
        var result = ClipboardHandler.ExecuteBuiltin("$md", "`code`");
        result.Should().NotContain("`");
        result.Should().Contain("code");
    }

    // ─── 알 수 없는 키 ──────────────────────────────────────────────────────

    [Fact]
    public void UnknownKey_ReturnsNull()
    {
        ClipboardHandler.ExecuteBuiltin("$unknown", "input").Should().BeNull();
    }

    [Fact]
    public void EmptyKey_ReturnsNull()
    {
        ClipboardHandler.ExecuteBuiltin("", "input").Should().BeNull();
    }
}
