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

namespace AxCopilot.Views;

public partial class ChatWindow
{
    // ─── 에이전트 스티키 진행률 바 ──────────────────────────────────────────

    private DateTime _progressStartTime;
    private DispatcherTimer? _progressElapsedTimer;

    private void UpdateAgentProgressBar(AgentEvent evt)
    {
        switch (evt.Type)
        {
            case AgentEventType.Planning when evt.Steps is { Count: > 0 }:
                ShowStickyProgress(evt.Steps.Count);
                break;

            case AgentEventType.StepStart when evt.StepTotal > 0:
                UpdateStickyProgress(evt.StepCurrent, evt.StepTotal, evt.Summary);
                break;

            case AgentEventType.Complete:
                HideStickyProgress();
                break;
        }
    }

    private void ShowStickyProgress(int totalSteps)
    {
        _progressStartTime = DateTime.Now;
        AgentProgressBar.Visibility = Visibility.Visible;
        ProgressIcon.Text = "\uE768"; // play
        ProgressStepLabel.Text = $"작업 준비 중... (0/{totalSteps})";
        ProgressPercent.Text = "0%";
        ProgressElapsed.Text = "0:00";
        ProgressFill.Width = 0;

        // 경과 시간 타이머
        _progressElapsedTimer?.Stop();
        _progressElapsedTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
        _progressElapsedTimer.Tick += (_, _) =>
        {
            var elapsed = DateTime.Now - _progressStartTime;
            ProgressElapsed.Text = elapsed.TotalHours >= 1
                ? elapsed.ToString(@"h\:mm\:ss")
                : elapsed.ToString(@"m\:ss");
        };
        _progressElapsedTimer.Start();
    }

    private void UpdateStickyProgress(int currentStep, int totalSteps, string stepDescription)
    {
        if (AgentProgressBar.Visibility != Visibility.Visible) return;

        var pct = totalSteps > 0 ? (double)currentStep / totalSteps : 0;
        ProgressStepLabel.Text = $"{stepDescription} ({currentStep}/{totalSteps})";
        ProgressPercent.Text = $"{(int)(pct * 100)}%";

        // 프로그레스 바 너비 애니메이션
        var parentBorder = ProgressFill.Parent as Border;
        if (parentBorder != null)
        {
            var targetWidth = parentBorder.ActualWidth * pct;
            var anim = new System.Windows.Media.Animation.DoubleAnimation(
                ProgressFill.Width, targetWidth, TimeSpan.FromMilliseconds(300))
            {
                EasingFunction = new System.Windows.Media.Animation.QuadraticEase(),
            };
            ProgressFill.BeginAnimation(WidthProperty, anim);
        }
    }

    private void HideStickyProgress()
    {
        _progressElapsedTimer?.Stop();
        _progressElapsedTimer = null;

        if (AgentProgressBar.Visibility != Visibility.Visible) return;

        // 완료 표시 후 페이드아웃
        ProgressIcon.Text = "\uE930"; // check
        ProgressStepLabel.Text = "작업 완료";
        ProgressPercent.Text = "100%";

        // 프로그레스 바 100%
        var parentBorder = ProgressFill.Parent as Border;
        if (parentBorder != null)
        {
            var anim = new System.Windows.Media.Animation.DoubleAnimation(
                ProgressFill.Width, parentBorder.ActualWidth, TimeSpan.FromMilliseconds(200));
            ProgressFill.BeginAnimation(WidthProperty, anim);
        }

        // 3초 후 숨기기
        var hideTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(3) };
        hideTimer.Tick += (_, _) =>
        {
            hideTimer.Stop();
            var fadeOut = new System.Windows.Media.Animation.DoubleAnimation(1, 0, TimeSpan.FromMilliseconds(300));
            fadeOut.Completed += (_, _) =>
            {
                AgentProgressBar.Visibility = Visibility.Collapsed;
                AgentProgressBar.Opacity = 1;
                ProgressFill.BeginAnimation(WidthProperty, null);
                ProgressFill.Width = 0;
            };
            AgentProgressBar.BeginAnimation(UIElement.OpacityProperty, fadeOut);
        };
        hideTimer.Start();
    }

    // ─── 파일 탐색기 ──────────────────────────────────────────────────────

    private static readonly HashSet<string> _ignoredDirs = new(StringComparer.OrdinalIgnoreCase)
    {
        "bin", "obj", "node_modules", ".git", ".vs", ".idea", ".vscode",
        "__pycache__", ".mypy_cache", ".pytest_cache", "dist", "build",
        ".cache", ".next", ".nuxt", "coverage", ".terraform",
    };

    private DispatcherTimer? _fileBrowserRefreshTimer;

    private void ToggleFileBrowser()
    {
        if (FileBrowserPanel.Visibility == Visibility.Visible)
        {
            FileBrowserPanel.Visibility = Visibility.Collapsed;
            Llm.ShowFileBrowser = false;
        }
        else
        {
            FileBrowserPanel.Visibility = Visibility.Visible;
            Llm.ShowFileBrowser = true;
            BuildFileTree();
        }
        _settings.Save();
    }

    private void BtnFileBrowserRefresh_Click(object sender, RoutedEventArgs e) => BuildFileTree();

    private void BtnFileBrowserOpenFolder_Click(object sender, RoutedEventArgs e)
    {
        var folder = GetCurrentWorkFolder();
        if (string.IsNullOrEmpty(folder) || !System.IO.Directory.Exists(folder)) return;
        try { System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = folder, UseShellExecute = true }); } catch (Exception) { /* 폴더 열기 실패 */ }
    }

    private void BtnFileBrowserClose_Click(object sender, RoutedEventArgs e)
    {
        FileBrowserPanel.Visibility = Visibility.Collapsed;
    }

    private void BuildFileTree()
    {
        FileTreeView.Items.Clear();
        var folder = GetCurrentWorkFolder();
        if (string.IsNullOrEmpty(folder) || !System.IO.Directory.Exists(folder))
        {
            FileTreeView.Items.Add(new TreeViewItem { Header = "작업 폴더를 선택하세요", IsEnabled = false });
            return;
        }

        FileBrowserTitle.Text = $"파일 탐색기 — {System.IO.Path.GetFileName(folder)}";
        var count = 0;
        PopulateDirectory(new System.IO.DirectoryInfo(folder), FileTreeView.Items, 0, ref count);
    }

    private void PopulateDirectory(System.IO.DirectoryInfo dir, ItemCollection items, int depth, ref int count)
    {
        if (depth > 4 || count > 200) return;

        // 디렉터리
        try
        {
            foreach (var subDir in dir.GetDirectories().OrderBy(d => d.Name))
            {
                if (count > 200) break;
                if (_ignoredDirs.Contains(subDir.Name) || subDir.Name.StartsWith('.')) continue;

                count++;
                var dirItem = new TreeViewItem
                {
                    Header = CreateFileTreeHeader("\uED25", subDir.Name, null),
                    Tag = subDir.FullName,
                    IsExpanded = depth < 1,
                };

                // 지연 로딩: 더미 자식 → 펼칠 때 실제 로드
                if (depth < 3)
                {
                    dirItem.Items.Add(new TreeViewItem { Header = "로딩 중..." }); // 더미
                    var capturedDir = subDir;
                    var capturedDepth = depth;
                    dirItem.Expanded += (s, _) =>
                    {
                        if (s is TreeViewItem ti && ti.Items.Count == 1 && ti.Items[0] is TreeViewItem d && d.Header?.ToString() == "로딩 중...")
                        {
                            ti.Items.Clear();
                            int c = 0;
                            PopulateDirectory(capturedDir, ti.Items, capturedDepth + 1, ref c);
                        }
                    };
                }
                else
                {
                    PopulateDirectory(subDir, dirItem.Items, depth + 1, ref count);
                }

                items.Add(dirItem);
            }
        }
        catch (Exception) { /* 비핵심 작업 실패 — UI 차단 방지 */ }

        // 파일
        try
        {
            foreach (var file in dir.GetFiles().OrderBy(f => f.Name))
            {
                if (count > 200) break;
                count++;

                var ext = file.Extension.ToLowerInvariant();
                var icon = GetFileIcon(ext);
                var size = FormatFileSize(file.Length);

                var fileItem = new TreeViewItem
                {
                    Header = CreateFileTreeHeader(icon, file.Name, size),
                    Tag = file.FullName,
                };

                // 더블클릭 → 프리뷰
                var capturedPath = file.FullName;
                fileItem.MouseDoubleClick += (s, e) =>
                {
                    e.Handled = true;
                    TryShowPreview(capturedPath);
                };

                // 우클릭 → 컨텍스트 메뉴 (MouseRightButtonUp에서 열어야 Popup이 바로 닫히지 않음)
                fileItem.MouseRightButtonUp += (s, e) =>
                {
                    e.Handled = true;
                    if (s is TreeViewItem ti) ti.IsSelected = true;
                    ShowFileTreeContextMenu(capturedPath);
                };

                items.Add(fileItem);
            }
        }
        catch (Exception) { /* 비핵심 작업 실패 — UI 차단 방지 */ }
    }

    private static StackPanel CreateFileTreeHeader(string icon, string name, string? sizeText)
    {
        var sp = new StackPanel { Orientation = Orientation.Horizontal };
        sp.Children.Add(new TextBlock
        {
            Text = icon,
            FontFamily = ThemeResourceHelper.SegoeMdl2,
            FontSize = 11,
            Foreground = new SolidColorBrush(Color.FromRgb(0x9C, 0xA3, 0xAF)),
            VerticalAlignment = VerticalAlignment.Center,
            Margin = new Thickness(0, 0, 5, 0),
        });
        sp.Children.Add(new TextBlock
        {
            Text = name,
            FontSize = 11.5,
            VerticalAlignment = VerticalAlignment.Center,
        });
        if (sizeText != null)
        {
            sp.Children.Add(new TextBlock
            {
                Text = $"  {sizeText}",
                FontSize = 10,
                Foreground = new SolidColorBrush(Color.FromRgb(0x6B, 0x72, 0x80)),
                VerticalAlignment = VerticalAlignment.Center,
            });
        }
        return sp;
    }

    private static string GetFileIcon(string ext) => ext switch
    {
        ".html" or ".htm" => "\uEB41",
        ".xlsx" or ".xls" => "\uE9F9",
        ".docx" or ".doc" => "\uE8A5",
        ".pdf" => "\uEA90",
        ".csv" => "\uE80A",
        ".md" => "\uE70B",
        ".json" or ".xml" => "\uE943",
        ".png" or ".jpg" or ".jpeg" or ".gif" or ".svg" or ".webp" => "\uEB9F",
        ".cs" or ".py" or ".js" or ".ts" or ".java" or ".cpp" => "\uE943",
        ".bat" or ".cmd" or ".ps1" or ".sh" => "\uE756",
        ".txt" or ".log" => "\uE8A5",
        _ => "\uE7C3",
    };

    private static string FormatFileSize(long bytes) => bytes switch
    {
        < 1024 => $"{bytes} B",
        < 1024 * 1024 => $"{bytes / 1024.0:F1} KB",
        _ => $"{bytes / (1024.0 * 1024.0):F1} MB",
    };

    private void ShowFileTreeContextMenu(string filePath)
    {
        var primaryText = ThemeResourceHelper.Primary(this);
        var secondaryText = ThemeResourceHelper.Secondary(this);
        var hoverBg = ThemeResourceHelper.Hint(this);
        var dangerBrush = new SolidColorBrush(Color.FromRgb(0xE7, 0x4C, 0x3C));

        var (popup, panel) = PopupMenuHelper.Create(this, this, PlacementMode.MousePoint, minWidth: 200);

        void AddItem(string icon, string label, Action action, Brush? labelColor = null, Brush? iconColor = null)
            => panel.Children.Add(PopupMenuHelper.MenuItem(label, labelColor ?? primaryText, hoverBg,
                () => { popup.IsOpen = false; action(); },
                icon: icon, iconColor: iconColor ?? secondaryText, fontSize: 12.5));

        void AddSep() => panel.Children.Add(PopupMenuHelper.Separator());

        var ext = System.IO.Path.GetExtension(filePath).ToLowerInvariant();
        if (_previewableExtensions.Contains(ext))
            AddItem("\uE8A1", "미리보기", () => ShowPreviewPanel(filePath));

        AddItem("\uE8A7", "외부 프로그램으로 열기", () =>
        {
            try { System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo { FileName = filePath, UseShellExecute = true }); } catch (Exception) { /* 파일 열기 실패 */ }
        });
        AddItem("\uED25", "폴더에서 보기", () =>
        {
            try { System.Diagnostics.Process.Start("explorer.exe", $"/select,\"{filePath}\""); } catch (Exception) { /* 탐색기 열기 실패 */ }
        });
        AddItem("\uE8C8", "경로 복사", () =>
        {
            try { Clipboard.SetText(filePath); ShowToast("경로 복사됨"); } catch (Exception) { /* 클립보드 접근 실패 */ }
        });

        AddSep();

        // 이름 변경
        AddItem("\uE8AC", "이름 변경", () =>
        {
            var dir = System.IO.Path.GetDirectoryName(filePath) ?? "";
            var oldName = System.IO.Path.GetFileName(filePath);
            var dlg = new Views.InputDialog("이름 변경", "새 파일 이름:", oldName) { Owner = this };
            if (dlg.ShowDialog() == true && !string.IsNullOrWhiteSpace(dlg.ResponseText))
            {
                var newPath = System.IO.Path.Combine(dir, dlg.ResponseText.Trim());
                try
                {
                    System.IO.File.Move(filePath, newPath);
                    BuildFileTree();
                    ShowToast($"이름 변경: {dlg.ResponseText.Trim()}");
                }
                catch (Exception ex) { ShowToast($"이름 변경 실패: {ex.Message}", "\uE783"); }
            }
        });

        // 삭제
        AddItem("\uE74D", "삭제", () =>
        {
            var result = MessageBox.Show(
                $"파일을 삭제하시겠습니까?\n{System.IO.Path.GetFileName(filePath)}",
                "파일 삭제 확인", MessageBoxButton.YesNo, MessageBoxImage.Warning);
            if (result == MessageBoxResult.Yes)
            {
                try
                {
                    System.IO.File.Delete(filePath);
                    BuildFileTree();
                    ShowToast("파일 삭제됨");
                }
                catch (Exception ex) { ShowToast($"삭제 실패: {ex.Message}", "\uE783"); }
            }
        }, dangerBrush, dangerBrush);

        // Dispatcher로 열어야 MouseRightButtonUp 후 바로 닫히지 않음
        Dispatcher.BeginInvoke(() => { popup.IsOpen = true; },
            System.Windows.Threading.DispatcherPriority.Input);
    }

    /// <summary>에이전트가 파일 생성 시 파일 탐색기를 자동 새로고침합니다.</summary>
    private void RefreshFileTreeIfVisible()
    {
        if (FileBrowserPanel.Visibility != Visibility.Visible) return;

        // 디바운스: 500ms 내 중복 호출 방지
        _fileBrowserRefreshTimer?.Stop();
        _fileBrowserRefreshTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(500) };
        _fileBrowserRefreshTimer.Tick += (_, _) =>
        {
            _fileBrowserRefreshTimer.Stop();
            BuildFileTree();
        };
        _fileBrowserRefreshTimer.Start();
    }
}
