using System.Diagnostics;
using System.Net.Http;
using System.Text;
using System.Windows;
using AxCopilot.SDK;
using AxCopilot.Services;
using AxCopilot.Themes;

namespace AxCopilot.Handlers;

/// <summary>
/// L12-1: HTTP 요청 테스터 핸들러. "http" 프리픽스로 사용합니다.
///
/// 예: http example.com            → GET 요청 (http:// 자동 추가)
///     http https://api.example    → GET 요청 + 응답 코드·시간
///     http head https://example   → HEAD 요청
///     http post https://example   → POST (빈 바디)
///     http 192.168.1.1            → 내부 IP GET
/// Enter → 응답 요약을 클립보드에 복사.
///
/// ⚠ 외부 URL: 사내 모드 차단. 내부 IP(10./192.168./172.16-31.)는 허용.
/// </summary>
public class HttpTesterHandler : IActionHandler
{
    public string? Prefix => "http";

    public PluginMetadata Metadata => new(
        "HTTP",
        "HTTP 요청 테스터 — GET · HEAD · POST · 응답 코드",
        "1.0",
        "AX");

    private static readonly HttpClient _client = new(new HttpClientHandler
    {
        AllowAutoRedirect  = true,
        MaxAutomaticRedirections = 3,
        ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
    })
    {
        Timeout = TimeSpan.FromSeconds(10),
    };

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

        if (string.IsNullOrWhiteSpace(q))
        {
            items.Add(new LauncherItem("HTTP 요청 테스터",
                "예: http example.com  /  http head https://api  /  http post https://url",
                null, null, Symbol: "\uE774"));
            items.Add(new LauncherItem("http localhost",        "로컬 서버 GET",   null, null, Symbol: "\uE774"));
            items.Add(new LauncherItem("http 192.168.1.1",      "내부 IP GET",     null, null, Symbol: "\uE774"));
            items.Add(new LauncherItem("http head https://…",   "HEAD 요청",       null, null, Symbol: "\uE774"));
            items.Add(new LauncherItem("http post https://…",   "POST 요청",       null, null, Symbol: "\uE774"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        var parts  = q.Split(' ', 2, StringSplitOptions.RemoveEmptyEntries);
        string method, url;

        if (parts[0].ToUpperInvariant() is "GET" or "HEAD" or "POST" or "PUT" or "DELETE" or "OPTIONS")
        {
            method = parts[0].ToUpperInvariant();
            url    = parts.Length > 1 ? parts[1].Trim() : "";
        }
        else
        {
            method = "GET";
            url    = q;
        }

        if (string.IsNullOrWhiteSpace(url))
        {
            items.Add(new LauncherItem("URL을 입력하세요", $"예: http {method.ToLower()} https://example.com", null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        // 스키마 자동 추가
        if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
            !url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
        {
            url = "http://" + url;
        }

        // 사내 모드 확인
        var settings   = (System.Windows.Application.Current as App)?.SettingsService?.Settings;
        var isInternal = settings?.InternalModeEnabled ?? true;
        if (isInternal && !IsInternalUrl(url))
        {
            items.Add(new LauncherItem(
                "사내 모드 제한",
                $"외부 URL '{url}'은 차단됩니다. 설정에서 사외 모드를 활성화하세요.",
                null, null, Symbol: "\uE783"));
            return Task.FromResult<IEnumerable<LauncherItem>>(items);
        }

        items.Add(new LauncherItem(
            $"{method}  {TruncateUrl(url)}",
            "Enter를 눌러 요청 실행",
            null,
            ("request", $"{method}|{url}"),
            Symbol: "\uE774"));

        return Task.FromResult<IEnumerable<LauncherItem>>(items);
    }

    public async Task ExecuteAsync(LauncherItem item, CancellationToken ct)
    {
        if (item.Data is ("copy", string text))
        {
            try
            {
                System.Windows.Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(text));
                NotificationService.Notify("HTTP", "클립보드에 복사했습니다.");
            }
            catch { /* 비핵심 */ }
            return;
        }

        if (item.Data is not ("request", string reqData)) return;

        var idx    = reqData.IndexOf('|');
        var method = reqData[..idx];
        var url    = reqData[(idx + 1)..];

        NotificationService.Notify("HTTP", $"{method} {TruncateUrl(url)} 요청 중…");

        try
        {
            var sw  = Stopwatch.StartNew();
            HttpResponseMessage resp;

            using var reqMsg = new HttpRequestMessage(new HttpMethod(method), url);
            reqMsg.Headers.TryAddWithoutValidation("User-Agent", "AX-Copilot/2.0 HTTP-Tester");

            resp = await _client.SendAsync(reqMsg, HttpCompletionOption.ResponseHeadersRead, ct);
            sw.Stop();

            var sb = new StringBuilder();
            sb.AppendLine($"URL:       {url}");
            sb.AppendLine($"메서드:     {method}");
            sb.AppendLine($"상태 코드:  {(int)resp.StatusCode} {resp.ReasonPhrase}");
            sb.AppendLine($"응답 시간:  {sw.ElapsedMilliseconds}ms");
            sb.AppendLine($"Content-Type: {resp.Content.Headers.ContentType}");
            sb.AppendLine($"Content-Length: {resp.Content.Headers.ContentLength?.ToString() ?? "unknown"}");

            // 주요 헤더
            foreach (var h in new[] { "Server", "X-Powered-By", "Cache-Control", "ETag", "Last-Modified" })
                if (resp.Headers.TryGetValues(h, out var vals))
                    sb.AppendLine($"{h}: {string.Join(", ", vals)}");

            var summary = sb.ToString().TrimEnd();
            System.Windows.Application.Current.Dispatcher.Invoke(() => Clipboard.SetText(summary));

            var status = (int)resp.StatusCode;
            var emoji  = status < 300 ? "✔" : status < 400 ? "↪" : "✘";
            NotificationService.Notify("HTTP",
                $"{emoji} {status} {resp.ReasonPhrase}  ({sw.ElapsedMilliseconds}ms)  · 결과 복사됨");
        }
        catch (TaskCanceledException)
        {
            NotificationService.Notify("HTTP", "요청 타임아웃 (10초 초과)");
        }
        catch (HttpRequestException ex)
        {
            NotificationService.Notify("HTTP", $"요청 오류: {ex.Message}");
        }
        catch (Exception ex)
        {
            NotificationService.Notify("HTTP", $"오류: {ex.Message}");
        }
    }

    // ── 헬퍼 ─────────────────────────────────────────────────────────────────

    private static bool IsInternalUrl(string url)
    {
        var lower = url.ToLowerInvariant();
        return lower.Contains("://localhost") ||
               lower.Contains("://127.0.0.1") ||
               lower.Contains("://192.168.") ||
               lower.Contains("://10.") ||
               System.Text.RegularExpressions.Regex.IsMatch(lower,
                   @"://172\.(1[6-9]|2\d|3[01])\.");
    }

    private static string TruncateUrl(string url) =>
        url.Length > 60 ? url[..60] + "…" : url;
}
