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

namespace AxCopilot.Views;

public partial class ChatWindow
{
    private StackPanel CreateStreamingContainer(out TextBlock streamText)
    {
        var msgMaxWidth = GetMessageMaxWidth();
        var container = new StackPanel
        {
            HorizontalAlignment = HorizontalAlignment.Left,
            Width = msgMaxWidth,
            MaxWidth = msgMaxWidth,
            Margin = new Thickness(40, 8, 80, 8),
            Opacity = 0,
            RenderTransform = new TranslateTransform(0, 10)
        };

        // 컨테이너 페이드인 + 슬라이드 업
        container.BeginAnimation(UIElement.OpacityProperty,
            new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(280)));
        ((TranslateTransform)container.RenderTransform).BeginAnimation(
            TranslateTransform.YProperty,
            new DoubleAnimation(10, 0, TimeSpan.FromMilliseconds(300))
            { EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut } });

        var headerGrid = new Grid { Margin = new Thickness(0, 0, 0, 4) };
        headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
        headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });

        var aiIcon = new TextBlock
        {
            Text = "\uE8BD", FontFamily = ThemeResourceHelper.SegoeMdl2, FontSize = 12,
            Foreground = ThemeResourceHelper.Accent(this),
            VerticalAlignment = VerticalAlignment.Center
        };
        // AI 아이콘 펄스 애니메이션 (응답 대기 중)
        aiIcon.BeginAnimation(UIElement.OpacityProperty,
            new DoubleAnimation(1.0, 0.35, TimeSpan.FromMilliseconds(700))
            { AutoReverse = true, RepeatBehavior = RepeatBehavior.Forever,
              EasingFunction = new SineEase() });
        _activeAiIcon = aiIcon;
        Grid.SetColumn(aiIcon, 0);
        headerGrid.Children.Add(aiIcon);

        var (streamAgentName, _, _) = GetAgentIdentity();
        var aiNameTb = new TextBlock
        {
            Text = streamAgentName, FontSize = 11, FontWeight = FontWeights.SemiBold,
            Foreground = ThemeResourceHelper.Accent(this),
            Margin = new Thickness(6, 0, 0, 0), VerticalAlignment = VerticalAlignment.Center
        };
        Grid.SetColumn(aiNameTb, 1);
        headerGrid.Children.Add(aiNameTb);

        // 실시간 경과 시간 (헤더 우측)
        _elapsedLabel = new TextBlock
        {
            Text = "0s",
            FontSize = 10.5,
            Foreground = ThemeResourceHelper.Secondary(this),
            HorizontalAlignment = HorizontalAlignment.Right,
            VerticalAlignment = VerticalAlignment.Center,
            Opacity = 0.5,
        };
        Grid.SetColumn(_elapsedLabel, 2);
        headerGrid.Children.Add(_elapsedLabel);

        container.Children.Add(headerGrid);

        streamText = new TextBlock
        {
            Text = "\u258c", // 블록 커서만 표시 (첫 청크 전)
            FontSize = 13.5,
            Foreground = ThemeResourceHelper.Secondary(this),
            TextWrapping = TextWrapping.Wrap, LineHeight = 22,
        };
        container.Children.Add(streamText);
        return container;
    }

    // ─── 스트리밍 완료 후 마크다운 렌더링으로 교체 ───────────────────────

    private void FinalizeStreamingContainer(StackPanel container, TextBlock streamText, string finalContent, ChatMessage? message = null)
    {
        // 스트리밍 plaintext 블록 제거
        container.Children.Remove(streamText);

        // 마크다운 렌더링
        var primaryText   = ThemeResourceHelper.Primary(this);
        var secondaryText = ThemeResourceHelper.Secondary(this);
        var accentBrush   = ThemeResourceHelper.Accent(this);
        var codeBgBrush   = ThemeResourceHelper.Hint(this);

        var mdPanel = MarkdownRenderer.Render(finalContent, primaryText, secondaryText, accentBrush, codeBgBrush);
        mdPanel.Margin = new Thickness(0, 0, 0, 4);
        mdPanel.Opacity = 0;
        container.Children.Add(mdPanel);
        mdPanel.BeginAnimation(UIElement.OpacityProperty,
            new DoubleAnimation(0, 1, TimeSpan.FromMilliseconds(180)));

        // 액션 버튼 바 + 토큰 표시
        var btnColor = ThemeResourceHelper.Secondary(this);
        var capturedContent = finalContent;
        var actionBar = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            HorizontalAlignment = HorizontalAlignment.Left,
            Margin = new Thickness(0, 6, 0, 0)
        };
        actionBar.Children.Add(CreateActionButton("\uE8C8", "복사", btnColor, () =>
        {
            try { Clipboard.SetText(capturedContent); } catch (Exception) { /* 클립보드 접근 실패 */ }
        }));
        actionBar.Children.Add(CreateActionButton("\uE72C", "다시 생성", btnColor, () => _ = RegenerateLastAsync()));
        actionBar.Children.Add(CreateActionButton("\uE70F", "수정 후 재시도", btnColor, () => ShowRetryWithFeedbackInput()));
        AddLinkedFeedbackButtons(actionBar, btnColor, message);

        container.Children.Add(actionBar);

        // 경과 시간 + 토큰 사용량 (우측 하단, 별도 줄)
        var elapsed = DateTime.UtcNow - _streamStartTime;
        var elapsedText = elapsed.TotalSeconds < 60
            ? $"{elapsed.TotalSeconds:0.#}s"
            : $"{(int)elapsed.TotalMinutes}m {elapsed.Seconds}s";

        var usage = _llm.LastTokenUsage;
        // 에이전트 루프(Cowork/Code)에서는 누적 토큰 사용, 일반 대화에서는 마지막 호출 토큰 사용
        var isAgentTab = _activeTab is "Cowork" or "Code";
        var displayInput = isAgentTab && _agentCumulativeInputTokens > 0
            ? _agentCumulativeInputTokens
            : usage?.PromptTokens ?? 0;
        var displayOutput = isAgentTab && _agentCumulativeOutputTokens > 0
            ? _agentCumulativeOutputTokens
            : usage?.CompletionTokens ?? 0;

        if (displayInput > 0 || displayOutput > 0)
        {
            UpdateStatusTokens(displayInput, displayOutput);
            Services.UsageStatisticsService.RecordTokens(displayInput, displayOutput);
        }
        string tokenText;
        if (displayInput > 0 || displayOutput > 0)
            tokenText = $"{FormatTokenCount(displayInput)} + {FormatTokenCount(displayOutput)} = {FormatTokenCount(displayInput + displayOutput)} tokens";
        else if (usage != null)
            tokenText = $"{FormatTokenCount(usage.PromptTokens)} + {FormatTokenCount(usage.CompletionTokens)} = {FormatTokenCount(usage.TotalTokens)} tokens";
        else
            tokenText = $"~{FormatTokenCount(EstimateTokenCount(finalContent))} tokens";

        var metaText = new TextBlock
        {
            Text = $"{elapsedText}  ·  {tokenText}",
            FontSize = 10.5,
            Foreground = ThemeResourceHelper.Secondary(this),
            HorizontalAlignment = HorizontalAlignment.Right,
            Margin = new Thickness(0, 6, 0, 0),
            Opacity = 0.6,
        };
        container.Children.Add(metaText);

        // Suggestion chips — AI가 번호 선택지를 제시한 경우 클릭 가능 버튼 표시
        var chips = ParseSuggestionChips(finalContent);
        if (chips.Count > 0)
        {
            var chipPanel = new WrapPanel
            {
                Margin = new Thickness(0, 8, 0, 4),
                HorizontalAlignment = HorizontalAlignment.Left,
            };
            foreach (var (num, label) in chips)
            {
                var chipBorder = new Border
                {
                    Background = ThemeResourceHelper.ItemBg(this),
                    BorderBrush = ThemeResourceHelper.Border(this),
                    BorderThickness = new Thickness(1),
                    CornerRadius = new CornerRadius(16),
                    Padding = new Thickness(14, 7, 14, 7),
                    Margin = new Thickness(0, 0, 8, 6),
                    Cursor = Cursors.Hand,
                    RenderTransformOrigin = new Point(0.5, 0.5),
                    RenderTransform = new ScaleTransform(1, 1),
                };
                chipBorder.Child = new TextBlock
                {
                    Text = $"{num}. {label}",
                    FontSize = 12.5,
                    Foreground = ThemeResourceHelper.Primary(this),
                };

                var chipHover = ThemeResourceHelper.HoverBg(this);
                var chipNormal = ThemeResourceHelper.ItemBg(this);
                chipBorder.MouseEnter += (s, _) =>
                {
                    if (s is Border b && b.RenderTransform is ScaleTransform st)
                    { st.ScaleX = 1.02; st.ScaleY = 1.02; b.Background = chipHover; }
                };
                chipBorder.MouseLeave += (s, _) =>
                {
                    if (s is Border b && b.RenderTransform is ScaleTransform st)
                    { st.ScaleX = 1.0; st.ScaleY = 1.0; b.Background = chipNormal; }
                };

                var capturedLabel = $"{num}. {label}";
                var capturedPanel = chipPanel;
                chipBorder.MouseLeftButtonDown += (_, _) =>
                {
                    // 칩 패널 제거 (1회용)
                    if (capturedPanel.Parent is Panel parent)
                        parent.Children.Remove(capturedPanel);
                    // 선택한 옵션을 사용자 메시지로 전송
                    InputBox.Text = capturedLabel;
                    _ = SendMessageAsync();
                };
                chipPanel.Children.Add(chipBorder);
            }
            container.Children.Add(chipPanel);
        }
    }

    /// <summary>AI 응답에서 번호 선택지를 파싱합니다. (1. xxx / 2. xxx 패턴)</summary>
    private static List<(string Num, string Label)> ParseSuggestionChips(string content)
    {
        var chips = new List<(string, string)>();
        if (string.IsNullOrEmpty(content)) return chips;

        var lines = content.Split('\n');
        // 마지막 번호 목록 블록을 찾음 (연속된 번호 라인)
        var candidates = new List<(string, string)>();
        var lastBlockStart = -1;

        for (int i = 0; i < lines.Length; i++)
        {
            var line = lines[i].Trim();
            // "1. xxx", "2) xxx", "① xxx" 등 번호 패턴
            var m = System.Text.RegularExpressions.Regex.Match(line, @"^(\d+)[.\)]\s+(.+)$");
            if (m.Success)
            {
                if (lastBlockStart < 0 || i == lastBlockStart + candidates.Count)
                {
                    if (lastBlockStart < 0) { lastBlockStart = i; candidates.Clear(); }
                    candidates.Add((m.Groups[1].Value, m.Groups[2].Value.TrimEnd()));
                }
                else
                {
                    // 새로운 블록 시작
                    lastBlockStart = i;
                    candidates.Clear();
                    candidates.Add((m.Groups[1].Value, m.Groups[2].Value.TrimEnd()));
                }
            }
            else if (!string.IsNullOrWhiteSpace(line))
            {
                // 번호 목록이 아닌 줄이 나오면 블록 리셋
                lastBlockStart = -1;
                candidates.Clear();
            }
            // 빈 줄은 블록 유지 (번호 목록 사이 빈 줄 허용)
        }

        // 2개 이상 선택지, 10개 이하일 때만 chips로 표시
        if (candidates.Count >= 2 && candidates.Count <= 10)
            chips.AddRange(candidates);

        return chips;
    }

    /// <summary>토큰 수를 k/m 단위로 포맷</summary>
    private static string FormatTokenCount(int count) => count switch
    {
        >= 1_000_000 => $"{count / 1_000_000.0:0.#}m",
        >= 1_000 => $"{count / 1_000.0:0.#}k",
        _ => count.ToString(),
    };

    /// <summary>토큰 수 추정 (한국어~3자/토큰, 영어~4자/토큰, 혼합 평균 ~3자/토큰)</summary>
    private static int EstimateTokenCount(string text)
    {
        if (string.IsNullOrEmpty(text)) return 0;
        // 한국어 문자 비율에 따라 가중
        int cjk = 0;
        foreach (var c in text)
            if (c >= 0xAC00 && c <= 0xD7A3 || c >= 0x3000 && c <= 0x9FFF) cjk++;
        double ratio = text.Length > 0 ? (double)cjk / text.Length : 0;
        double charsPerToken = 4.0 - ratio * 2.0; // 영어 4, 한국어 2
        return Math.Max(1, (int)Math.Round(text.Length / charsPerToken));
    }

    // ─── 생성 중지 ──────────────────────────────────────────────────────

    private void StopGeneration()
    {
        _streamCts?.Cancel();
    }
}
