using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Threading;
using AxCopilot.Models;
using AxCopilot.Services;
using AxCopilot.Services.Agent;

namespace AxCopilot.Views;

public partial class ChatWindow
{
    // ─── 슬래시 명령어 ────────────────────────────────────────────────────

    // ── 슬래시 명령어 팝업 페이징 ──
    private int SlashPageSize => Math.Clamp(Llm.SlashPopupPageSize, 3, 20);
    private List<(string Cmd, string Label, bool IsSkill)> _slashAllMatches = [];
    private int _slashPageOffset = 0;
    private int _slashSelectedIndex = -1; // 팝업 내 키보드 선택 인덱스 (페이지 내 상대)

    // ── 슬래시 명령어 칩 ──
    private string? _activeSlashCmd = null;

    // ── 슬래시 명령어 (탭별 분류) ──

    /// <summary>공통 슬래시 명령어 — 모든 탭에서 사용 가능.</summary>
    private static readonly Dictionary<string, (string Label, string SystemPrompt, string Tab)> SlashCommands = new(StringComparer.OrdinalIgnoreCase)
    {
        // 공통
        ["/summary"]  = ("Summary",      "사용자가 제공한 내용을 핵심 포인트 위주로 간결하게 요약해 주세요. 불릿 포인트 형식을 사용하세요.", "all"),
        ["/translate"] = ("Translate",    "사용자가 제공한 텍스트를 영어로 번역해 주세요. 원문의 톤과 뉘앙스를 유지하세요.", "all"),
        ["/explain"]  = ("Explain",      "사용자가 제공한 내용을 쉽고 자세하게 설명해 주세요. 필요하면 예시를 포함하세요.", "all"),
        ["/fix"]      = ("Fix",          "사용자가 제공한 텍스트의 맞춤법, 문법, 자연스러운 표현을 교정해 주세요. 수정 사항을 명확히 표시하세요.", "all"),

        // Cowork/Code 전용
        ["/review"]   = ("Code Review",  "작업 폴더의 git diff를 분석하여 코드 리뷰를 수행해 주세요. code_review 도구를 사용하세요.", "dev"),
        ["/pr"]       = ("PR Summary",   "작업 폴더의 변경사항을 PR 설명 형식으로 요약해 주세요. code_review(action: pr_summary) 도구를 사용하세요.", "dev"),
        ["/test"]     = ("Test",         "작업 폴더의 코드에 대한 단위 테스트를 생성해 주세요. test_loop 도구를 사용하세요.", "dev"),
        ["/structure"] = ("Structure",   "작업 폴더의 프로젝트 구조를 분석하고 설명해 주세요. folder_map 도구를 사용하세요.", "dev"),
        ["/build"]    = ("Build",        "작업 폴더의 프로젝트를 빌드해 주세요. build_run 도구를 사용하세요.", "dev"),
        ["/search"]   = ("Search",       "작업 폴더에서 관련 코드를 검색해 주세요. search_codebase 도구를 사용하세요.", "dev"),

        // 특수
        ["/help"]     = ("Help",         "__HELP__", "all"),
    };

    private void InputBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        UpdateWatermarkVisibility();
        var text = InputBox.Text;

        // 칩이 활성화된 상태에서 사용자가 /를 타이핑하면 칩 해제
        if (_activeSlashCmd != null && text.StartsWith("/"))
            HideSlashChip(restoreText: false);

        if (text.StartsWith("/") && !text.Contains(' '))
        {
            // 탭별 필터링: Chat → "all"만, Cowork/Code → "all" + "dev"
            bool isDev = _activeTab is "Cowork" or "Code";

            // 내장 슬래시 명령어 매칭 (탭 필터)
            var matches = SlashCommands
                .Where(kv => kv.Key.StartsWith(text, StringComparison.OrdinalIgnoreCase))
                .Where(kv => kv.Value.Tab == "all" || (isDev && kv.Value.Tab == "dev"))
                .Select(kv => (Cmd: kv.Key, Label: kv.Value.Label, IsSkill: false))
                .ToList();

            // SlashCommandRegistry 명령 매칭 (/compact, /memory, /plan 등)
            foreach (var rm in GetRegistrySlashMatches(text))
            {
                // 내장 dict나 스킬에 이미 있는 것 제외 (중복 방지)
                if (!matches.Any(m => m.Cmd.Equals(rm.Cmd, StringComparison.OrdinalIgnoreCase)))
                    matches.Add(rm);
            }

            // 스킬 슬래시 명령어 매칭 (탭별 필터)
            if (Llm.EnableSkillSystem)
            {
                var skillMatches = SkillService.MatchSlashCommand(text)
                    .Where(s => s.IsVisibleInTab(_activeTab))
                    .Select(s => (Cmd: "/" + s.Name,
                        Label: s.IsAvailable ? s.Label : $"{s.Label} {s.UnavailableHint}",
                        IsSkill: true, Available: s.IsAvailable));
                foreach (var sm in skillMatches)
                    matches.Add((sm.Cmd, sm.Label, sm.IsSkill));
            }

            if (matches.Count > 0)
            {
                // 즐겨찾기를 상단에 고정 정렬
                var favorites = Llm.FavoriteSlashCommands;
                if (favorites.Count > 0)
                {
                    matches = matches
                        .OrderByDescending(m => favorites.Contains(m.Cmd, StringComparer.OrdinalIgnoreCase))
                        .ToList();
                }

                _slashAllMatches = matches;
                _slashPageOffset = 0;
                _slashSelectedIndex = -1;
                RenderSlashPage();
                SlashPopup.IsOpen = true;
                return;
            }
        }
        SlashPopup.IsOpen = false;
    }

    /// <summary>현재 페이지의 슬래시 명령어 항목을 렌더링합니다.</summary>
    private void RenderSlashPage()
    {
        SlashItems.Items.Clear();
        var total = _slashAllMatches.Count;
        var start = _slashPageOffset;
        var end   = Math.Min(start + SlashPageSize, total);

        // 위 화살표
        if (start > 0)
        {
            SlashNavUp.Visibility = Visibility.Visible;
            SlashNavUpText.Text   = $"▲  위로 {start}개";
        }
        else
            SlashNavUp.Visibility = Visibility.Collapsed;

        // 아이템 렌더링
        for (int i = start; i < end; i++)
        {
            var (cmd, label, isSkill) = _slashAllMatches[i];
            var capturedCmd   = cmd;
            var skillDef      = isSkill ? SkillService.Find(cmd.TrimStart('/')) : null;
            var skillAvailable = skillDef?.IsAvailable ?? true;

            var isFav = Llm.FavoriteSlashCommands
                .Contains(cmd, StringComparer.OrdinalIgnoreCase);

            var pageLocalIndex = i - start;
            var isSelected = pageLocalIndex == _slashSelectedIndex;
            var hoverBrushItem = ThemeResourceHelper.HoverBg(this);

            var item = new Border
            {
                Background  = isSelected ? hoverBrushItem : Brushes.Transparent,
                CornerRadius = new CornerRadius(6),
                Padding     = new Thickness(10, 6, 10, 6),
                Margin      = new Thickness(0, 1, 0, 1),
                Cursor      = skillAvailable ? Cursors.Hand : Cursors.Arrow,
                Opacity     = skillAvailable ? 1.0 : 0.5,
            };
            var itemGrid = new Grid();
            itemGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
            itemGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

            var stack = new StackPanel { Orientation = Orientation.Horizontal };
            if (isSkill)
            {
                stack.Children.Add(new TextBlock
                {
                    Text       = "\uE768 ",
                    FontFamily = ThemeResourceHelper.SegoeMdl2,
                    FontSize   = 11,
                    Foreground = skillAvailable
                        ? ThemeResourceHelper.Accent(this)
                        : ThemeResourceHelper.Secondary(this),
                    VerticalAlignment = VerticalAlignment.Center,
                });
            }
            if (isFav)
            {
                stack.Children.Add(new TextBlock
                {
                    Text       = "\uE735 ",
                    FontFamily = ThemeResourceHelper.SegoeMdl2,
                    FontSize   = 10,
                    Foreground = new SolidColorBrush(Color.FromRgb(0xF5, 0x9E, 0x0B)),
                    VerticalAlignment = VerticalAlignment.Center,
                    Margin = new Thickness(0, 0, 2, 0),
                });
            }
            stack.Children.Add(new TextBlock
            {
                Text       = cmd,
                FontSize   = 13,
                FontWeight = FontWeights.SemiBold,
                Foreground = skillAvailable
                    ? ThemeResourceHelper.Accent(this)
                    : ThemeResourceHelper.Secondary(this),
                VerticalAlignment = VerticalAlignment.Center,
            });
            stack.Children.Add(new TextBlock
            {
                Text      = $" — {label}",
                FontSize  = 12,
                Foreground = ThemeResourceHelper.Secondary(this),
                VerticalAlignment = VerticalAlignment.Center,
            });
            Grid.SetColumn(stack, 0);
            itemGrid.Children.Add(stack);

            // 즐겨찾기 토글 별 아이콘
            var favCapturedCmd = cmd;
            var favBtn = new Border
            {
                Width = 24, Height = 24,
                CornerRadius = new CornerRadius(4),
                Background = Brushes.Transparent,
                Cursor = Cursors.Hand,
                VerticalAlignment = VerticalAlignment.Center,
                Child = new TextBlock
                {
                    Text = isFav ? "\uE735" : "\uE734",
                    FontFamily = ThemeResourceHelper.SegoeMdl2,
                    FontSize = 11,
                    Foreground = isFav
                        ? new SolidColorBrush(Color.FromRgb(0xF5, 0x9E, 0x0B))
                        : ThemeResourceHelper.Secondary(this),
                    HorizontalAlignment = HorizontalAlignment.Center,
                    VerticalAlignment = VerticalAlignment.Center,
                    Opacity = isFav ? 1.0 : 0.4,
                },
            };
            favBtn.MouseEnter += (s, _) => ((Border)s).Opacity = 0.8;
            favBtn.MouseLeave += (s, _) => ((Border)s).Opacity = 1.0;
            favBtn.MouseLeftButtonDown += (_, me) =>
            {
                me.Handled = true; // 아이템 클릭 이벤트 방지
                ToggleSlashFavorite(favCapturedCmd);
            };
            Grid.SetColumn(favBtn, 1);
            itemGrid.Children.Add(favBtn);

            item.Child = itemGrid;

            if (skillAvailable)
            {
                var hoverBrush = ThemeResourceHelper.HoverBg(this);
                item.MouseEnter += (_, _) => item.Background = hoverBrush;
                item.MouseLeave += (_, _) => item.Background = Brushes.Transparent;
                item.MouseLeftButtonDown += (_, _) =>
                {
                    SlashPopup.IsOpen = false;
                    if (capturedCmd.Equals("/help", StringComparison.OrdinalIgnoreCase))
                    {
                        InputBox.Text = "";
                        ShowSlashHelpWindow();
                        return;
                    }
                    // 칩 표시: 명령어를 칩으로, InputBox는 빈 텍스트로
                    ShowSlashChip(capturedCmd);
                    InputBox.Focus();
                };
            }
            SlashItems.Items.Add(item);
        }

        // 아래 화살표
        if (end < total)
        {
            SlashNavDown.Visibility = Visibility.Visible;
            SlashNavDownText.Text   = $"▼  아래로 {total - end}개";
        }
        else
            SlashNavDown.Visibility = Visibility.Collapsed;
    }

    /// <summary>슬래시 팝업 마우스 휠 스크롤 처리.</summary>
    private void SlashPopup_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        e.Handled = true;
        SlashPopup_ScrollByDelta(e.Delta);
    }

    /// <summary>슬래시 팝업을 Delta 방향으로 스크롤합니다.</summary>
    private void SlashPopup_ScrollByDelta(int delta)
    {
        if (_slashAllMatches.Count == 0) return;
        var pageItemCount = Math.Min(SlashPageSize, _slashAllMatches.Count - _slashPageOffset);

        if (delta > 0) // 위로 스크롤 (Up 키)
        {
            if (_slashSelectedIndex > 0)
                _slashSelectedIndex--;
            else if (_slashSelectedIndex == 0 && _slashPageOffset > 0)
            {
                _slashPageOffset = Math.Max(0, _slashPageOffset - 1);
                _slashSelectedIndex = 0;
            }
        }
        else // 아래로 스크롤 (Down 키)
        {
            if (_slashSelectedIndex < 0)
            {
                // 초기 상태: 첫 번째 항목 선택
                _slashSelectedIndex = 0;
            }
            else if (_slashSelectedIndex < pageItemCount - 1)
                _slashSelectedIndex++;
            else if (_slashPageOffset + SlashPageSize < _slashAllMatches.Count)
            {
                _slashPageOffset++;
                _slashSelectedIndex = Math.Min(SlashPageSize - 1,
                    _slashAllMatches.Count - _slashPageOffset - 1);
            }
        }
        RenderSlashPage();
    }

    /// <summary>키보드로 선택된 슬래시 아이템을 실행합니다.</summary>
    private void ExecuteSlashSelectedItem()
    {
        var absoluteIdx = _slashPageOffset + _slashSelectedIndex;
        if (absoluteIdx < 0 || absoluteIdx >= _slashAllMatches.Count) return;

        var (cmd, _, isSkill) = _slashAllMatches[absoluteIdx];
        var skillDef = isSkill ? SkillService.Find(cmd.TrimStart('/')) : null;
        var skillAvailable = skillDef?.IsAvailable ?? true;
        if (!skillAvailable) return;

        SlashPopup.IsOpen = false;
        _slashSelectedIndex = -1;

        if (cmd.Equals("/help", StringComparison.OrdinalIgnoreCase))
        {
            InputBox.Text = "";
            ShowSlashHelpWindow();
            return;
        }
        ShowSlashChip(cmd);
        InputBox.Focus();
    }

    /// <summary>슬래시 명령어 즐겨찾기를 토글하고 설정을 저장합니다.</summary>
    private void ToggleSlashFavorite(string cmd)
    {
        var favs = Llm.FavoriteSlashCommands;
        var existing = favs.FirstOrDefault(f => f.Equals(cmd, StringComparison.OrdinalIgnoreCase));
        if (existing != null)
            favs.Remove(existing);
        else
            favs.Add(cmd);

        _settings.Save();

        // 팝업 새로고침: TextChanged 이벤트를 트리거하여 팝업 재렌더링
        var currentText = InputBox.Text;
        InputBox.TextChanged -= InputBox_TextChanged;
        InputBox.Text = "";
        InputBox.TextChanged += InputBox_TextChanged;
        InputBox.Text = currentText;
    }

    /// <summary>슬래시 명령어 칩을 표시하고 InputBox를 비웁니다.</summary>
    private void ShowSlashChip(string cmd)
    {
        _activeSlashCmd = cmd;
        SlashChipText.Text = cmd;
        SlashCommandChip.Visibility = Visibility.Visible;

        // 칩 너비 측정 후 InputBox 왼쪽 여백 조정
        SlashCommandChip.UpdateLayout();
        var chipRight = SlashCommandChip.Margin.Left + SlashCommandChip.ActualWidth + 6;
        InputBox.Padding = new Thickness(chipRight, 10, 14, 10);
        InputBox.Text = "";
    }

    /// <summary>슬래시 명령어 칩을 숨깁니다.</summary>
    /// <param name="restoreText">true이면 InputBox에 명령어 텍스트를 복원합니다.</param>
    private void HideSlashChip(bool restoreText = false)
    {
        if (_activeSlashCmd == null) return;
        var prev = _activeSlashCmd;
        _activeSlashCmd = null;
        SlashCommandChip.Visibility = Visibility.Collapsed;
        InputBox.Padding = new Thickness(14, 10, 14, 10);
        if (restoreText)
        {
            InputBox.Text = prev + " ";
            InputBox.CaretIndex = InputBox.Text.Length;
        }
    }

    /// <summary>슬래시 명령어를 감지하여 시스템 프롬프트와 사용자 텍스트를 분리합니다.</summary>
    private static (string? slashSystem, string userText) ParseSlashCommand(string input)
    {
        // 내장 명령어 우선
        foreach (var (cmd, (_, prompt, _)) in SlashCommands)
        {
            if (input.StartsWith(cmd, StringComparison.OrdinalIgnoreCase))
            {
                // __HELP__는 특수 처리 (ParseSlashCommand에서는 무시)
                if (prompt == "__HELP__") return (null, input);
                var rest = input[cmd.Length..].Trim();
                return (prompt, string.IsNullOrEmpty(rest) ? cmd : rest);
            }
        }

        // 스킬 명령어 매칭
        foreach (var skill in SkillService.Skills)
        {
            var slashCmd = "/" + skill.Name;
            if (input.StartsWith(slashCmd, StringComparison.OrdinalIgnoreCase))
            {
                var rest = input[slashCmd.Length..].Trim();
                return (skill.SystemPrompt, string.IsNullOrEmpty(rest) ? skill.Label : rest);
            }
        }

        return (null, input);
    }

    /// <summary>
    /// 외부에서 슬래시 명령을 입력창에 주입하여 실행합니다.
    /// AgentSettingsPanel 등에서 /hooks 조회 등에 사용합니다.
    /// </summary>
    public void InjectSlashCommand(string slashCmd)
    {
        Dispatcher.Invoke(() =>
        {
            SlashPopup.IsOpen = false;
            ShowSlashChip(slashCmd);
            InputBox.Text = "";
            _ = SendMessageAsync();
        });
    }
}
