using System.Security.Cryptography;
using System.Text;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// 인코딩/해싱 변환 핸들러. "encode " 프리픽스로 사용합니다.
/// 예: encode base64 hello          → aGVsbG8=
///     encode decode base64 aGVsbG8= → hello
///     encode url https://example.com → URL 인코딩
///     encode hex hello              → 68656c6c6f
///     encode md5 hello              → 5d41402abc4b2a76b9719d911017c592
///     encode sha256 hello           → 2cf24dba...
///     encode sha1 hello             → aaf4c61d...
///     encode (빈 쿼리)               → 지원 목록
/// </summary>
public class EncodeHandler : IActionHandler
{
    public string? Prefix => "encode ";   // 뒤에 공백 포함

    public PluginMetadata Metadata => new(
        "Encoder",
        "인코딩/해싱 — encode base64/url/hex/md5/sha256 텍스트",
        "1.0",
        "AX");

    public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
    {
        var q = query.Trim();

        if (string.IsNullOrWhiteSpace(q))
            return Task.FromResult(HelpItems());

        // "decode <타입> <값>" 파턴
        if (q.StartsWith("decode ", StringComparison.OrdinalIgnoreCase))
        {
            var rest = q[7..].Trim();
            return Task.FromResult(HandleDecode(rest));
        }

        // "<타입> <값>" 패턴
        var spaceIdx = q.IndexOf(' ');
        if (spaceIdx < 0)
            return Task.FromResult(HelpItems());

        var type = q[..spaceIdx].Trim().ToLowerInvariant();
        var input = q[(spaceIdx + 1)..];

        return Task.FromResult(HandleEncode(type, input));
    }

    private static IEnumerable<LauncherItem> HandleEncode(string type, string input)
    {
        try
        {
            return type switch
            {
                "base64" or "b64" => SingleResult("Base64 인코딩",
                    Convert.ToBase64String(Encoding.UTF8.GetBytes(input))),

                "url" => SingleResult("URL 인코딩",
                    Uri.EscapeDataString(input)),

                "hex" => SingleResult("HEX 인코딩",
                    Convert.ToHexString(Encoding.UTF8.GetBytes(input)).ToLowerInvariant()),

                "md5" => SingleResult("MD5 해시",
                    MD5Hash(input)),

                "sha1" => SingleResult("SHA-1 해시",
                    SHA1Hash(input)),

                "sha256" => SingleResult("SHA-256 해시",
                    SHA256Hash(input)),

                "sha512" => SingleResult("SHA-512 해시",
                    SHA512Hash(input)),

                "html" => SingleResult("HTML 엔티티 인코딩",
                    System.Net.WebUtility.HtmlEncode(input)),

                _ =>
                [
                    new LauncherItem(
                        $"알 수 없는 타입: {type}",
                        "base64, url, hex, md5, sha1, sha256, sha512, html 중 선택",
                        null, null, Symbol: Symbols.Warning)
                ]
            };
        }
        catch (Exception ex)
        {
            return
            [
                new LauncherItem("변환 오류", ex.Message, null, null, Symbol: Symbols.Error)
            ];
        }
    }

    private static IEnumerable<LauncherItem> HandleDecode(string rest)
    {
        var spaceIdx = rest.IndexOf(' ');
        if (spaceIdx < 0)
            return [new LauncherItem("사용법: encode decode <타입> <값>", "타입: base64, url, hex, html", null, null, Symbol: Symbols.Info)];

        var type = rest[..spaceIdx].Trim().ToLowerInvariant();
        var input = rest[(spaceIdx + 1)..];

        try
        {
            return type switch
            {
                "base64" or "b64" => SingleResult("Base64 디코딩",
                    Encoding.UTF8.GetString(Convert.FromBase64String(input))),

                "url" => SingleResult("URL 디코딩",
                    Uri.UnescapeDataString(input)),

                "hex" => SingleResult("HEX 디코딩",
                    Encoding.UTF8.GetString(Convert.FromHexString(input))),

                "html" => SingleResult("HTML 엔티티 디코딩",
                    System.Net.WebUtility.HtmlDecode(input)),

                _ =>
                [
                    new LauncherItem(
                        $"디코딩 불가 타입: {type}",
                        "디코딩 지원: base64, url, hex, html",
                        null, null, Symbol: Symbols.Warning)
                ]
            };
        }
        catch (Exception ex)
        {
            return
            [
                new LauncherItem("디코딩 오류", ex.Message, null, null, Symbol: Symbols.Error)
            ];
        }
    }

    private static IEnumerable<LauncherItem> SingleResult(string title, string result)
    {
        var preview = result.Length > 80 ? result[..77] + "…" : result;
        return
        [
            new LauncherItem(
                title,
                $"{preview}  ·  Enter로 복사",
                null,
                result,
                Symbol: Symbols.EncodeIcon)
        ];
    }

    private static IEnumerable<LauncherItem> HelpItems()
    {
        return
        [
            new LauncherItem("encode base64 <텍스트>",  "Base64 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
            new LauncherItem("encode url <텍스트>",     "URL 퍼센트 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
            new LauncherItem("encode hex <텍스트>",     "16진수 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
            new LauncherItem("encode md5 <텍스트>",     "MD5 해시 (단방향)", null, null, Symbol: Symbols.EncodeIcon),
            new LauncherItem("encode sha256 <텍스트>",  "SHA-256 해시 (단방향)", null, null, Symbol: Symbols.EncodeIcon),
            new LauncherItem("encode html <텍스트>",    "HTML 엔티티 인코딩/디코딩", null, null, Symbol: Symbols.EncodeIcon),
            new LauncherItem("encode decode base64 <값>", "Base64 디코딩 예시", null, null, Symbol: Symbols.EncodeIcon),
        ];
    }

    // ─── 해시 헬퍼 ─────────────────────────────────────────────────────────────

    private static string MD5Hash(string input)
    {
        var bytes = MD5.HashData(Encoding.UTF8.GetBytes(input));
        return Convert.ToHexString(bytes).ToLowerInvariant();
    }

    private static string SHA1Hash(string input)
    {
        var bytes = SHA1.HashData(Encoding.UTF8.GetBytes(input));
        return Convert.ToHexString(bytes).ToLowerInvariant();
    }

    private static string SHA256Hash(string input)
    {
        var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(input));
        return Convert.ToHexString(bytes).ToLowerInvariant();
    }

    private static string SHA512Hash(string input)
    {
        var bytes = SHA512.HashData(Encoding.UTF8.GetBytes(input));
        return Convert.ToHexString(bytes).ToLowerInvariant();
    }

    public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is string text)
        {
            try { Clipboard.SetText(text); } catch (Exception) { }
        }
        return Task.CompletedTask;
    }
}
