using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;
using AxCopilot.Services.Agent;
using AxCopilot.ViewModels;

namespace AxCopilot.Views;

/// <summary>
/// 에이전트 워크플로우 분석기.
/// 에이전트 실행 과정을 세로 타임라인 형태로 실시간 시각화합니다.
/// 개발자 모드 → 워크플로우 시각화 설정이 켜져있을 때 자동으로 열립니다.
/// </summary>
public partial class WorkflowAnalyzerWindow : Window
{
    private static App? CurrentApp => System.Windows.Application.Current as App;

    private readonly DateTime _startTime = DateTime.Now;
    private int _totalToolCalls;
    private int _totalInputTokens;
    private int _totalOutputTokens;
    private int _maxIteration;
    private int _successCount;
    private int _failCount;
    private string _logLevel = "simple";
    private bool _autoScroll = true;
    private string _activeTab = "timeline"; // timeline | bottleneck

    // 병목 분석 데이터 수집
    private readonly List<WaterfallEntry> _waterfallEntries = new();
    private readonly Dictionary<string, long> _toolTimeAccum = new();
    private readonly List<(int Iteration, int Input, int Output)> _tokenTrend = new();
    private long _lastEventMs; // 워터폴 시작 시간 기준

    // Phase 18-B: 리플레이 ViewModel
    private readonly ReplayTimelineViewModel _replayVm = new();

    // ─── 상하좌우 리사이즈 (WindowStyle=None 대응) ─────────────
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);

    private const int WM_NCHITTEST = 0x0084;
    private const int HTLEFT = 10, HTRIGHT = 11, HTTOP = 12, HTTOPLEFT = 13, HTTOPRIGHT = 14;
    private const int HTBOTTOM = 15, HTBOTTOMLEFT = 16, HTBOTTOMRIGHT = 17;

    public WorkflowAnalyzerWindow()
    {
        InitializeComponent();
        SourceInitialized += (_, _) =>
        {
            var hwndSource = (HwndSource)PresentationSource.FromVisual(this);
            hwndSource?.AddHook(WndProc);
        };

        // 로그 레벨 표시
        _logLevel = CurrentApp?.SettingsService?.Settings.Llm.AgentLogLevel ?? "simple";
        LogLevelBadge.Text = _logLevel switch
        {
            "debug" => "DEBUG",
            "detailed" => "DETAILED",
            _ => "SIMPLE",
        };

        // 시작 위치: 화면 우측 하단
        Loaded += (_, _) =>
        {
            var screen = SystemParameters.WorkArea;
            Left = screen.Right - ActualWidth - 20;
            Top = screen.Bottom - ActualHeight - 20;
            UpdateTabVisuals();
        };

        // 자동 스크롤 감지
        TimelineScroller.ScrollChanged += (_, e) =>
        {
            _autoScroll = Math.Abs(e.ExtentHeight - e.ViewportHeight - e.VerticalOffset) < 30;
        };
    }

    /// <summary>에이전트 이벤트를 수신하여 타임라인에 추가합니다.</summary>
    public void OnAgentEvent(AgentEvent evt)
    {
        if (!Dispatcher.CheckAccess())
        {
            Dispatcher.Invoke(() => OnAgentEvent(evt));
            return;
        }

        // 요약 카드 업데이트
        if (evt.Iteration > _maxIteration) _maxIteration = evt.Iteration;
        if (evt.InputTokens > 0) _totalInputTokens += evt.InputTokens;
        if (evt.OutputTokens > 0) _totalOutputTokens += evt.OutputTokens;

        if (evt.Type is AgentEventType.ToolCall)
            _totalToolCalls++;
        if (evt.Type is AgentEventType.ToolResult)
            _successCount++;
        if (evt.Type is AgentEventType.Error)
            _failCount++;

        UpdateSummaryCards();

        // ── 병목 분석 데이터 수집 ──
        CollectBottleneckData(evt);

        // 타임라인 노드 추가
        var node = CreateTimelineNode(evt);
        TimelinePanel.Children.Add(node);

        // 자동 스크롤
        if (_autoScroll)
            TimelineScroller.ScrollToEnd();

        // 상태 바
        StatusText.Text = evt.Type switch
        {
            AgentEventType.Complete => "✓ 완료",
            AgentEventType.Error => $"⚠ 오류: {Truncate(evt.Summary, 60)}",
            AgentEventType.ToolCall => $"실행 중: {evt.ToolName}",
            AgentEventType.Thinking => "사고 중...",
            AgentEventType.Planning => "계획 수립 중...",
            _ => StatusText.Text,
        };

        // 완료 시 병목 분석 차트 자동 갱신
        if (evt.Type == AgentEventType.Complete)
            RenderBottleneckCharts();
    }

    /// <summary>타임라인을 초기화합니다.</summary>
    public void Reset()
    {
        TimelinePanel.Children.Clear();
        DetailPanel.Visibility = Visibility.Collapsed;
        _totalToolCalls = 0;
        _totalInputTokens = 0;
        _totalOutputTokens = 0;
        _maxIteration = 0;
        _successCount = 0;
        _failCount = 0;
        _waterfallEntries.Clear();
        _toolTimeAccum.Clear();
        _tokenTrend.Clear();
        _lastEventMs = 0;
        UpdateSummaryCards();
        ClearBottleneckCharts();
        StatusText.Text = "대기 중...";
    }

    /// <summary>타임라인 탭을 활성화합니다.</summary>
    public void SwitchToTimelineTab()
    {
        _activeTab = "timeline";
        UpdateTabVisuals();
    }

    /// <summary>병목 분석 탭을 활성화합니다. 외부(ChatWindow)에서 호출합니다.</summary>
    public void SwitchToBottleneckTab()
    {
        _activeTab = "bottleneck";
        UpdateTabVisuals();
        RenderBottleneckCharts();
    }

    // ─── 탭 전환 ──────────────────────────────────────────────────

    private void TabTimeline_Click(object sender, MouseButtonEventArgs e)
    {
        _activeTab = "timeline";
        UpdateTabVisuals();
    }

    private void TabBottleneck_Click(object sender, MouseButtonEventArgs e)
    {
        _activeTab = "bottleneck";
        UpdateTabVisuals();
        RenderBottleneckCharts();
    }

    // Phase 18-B: 리플레이 탭 클릭
    private void TabReplay_Click(object sender, MouseButtonEventArgs e)
    {
        _activeTab = "replay";
        UpdateTabVisuals();
        LoadReplaySessions();
    }

    private void UpdateTabVisuals()
    {
        var accentBrush = TryFindResource("AccentColor") as Brush ?? Brushes.CornflowerBlue;
        var itemBg = TryFindResource("ItemBackground") as Brush
                     ?? new SolidColorBrush(Color.FromArgb(0x15, 0xFF, 0xFF, 0xFF));
        var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;

        var isTimeline  = _activeTab == "timeline";
        var isBottleneck = _activeTab == "bottleneck";
        var isReplay    = _activeTab == "replay";

        TabTimeline.Background  = isTimeline   ? accentBrush : itemBg;
        TabBottleneck.Background = isBottleneck ? accentBrush : itemBg;
        TabReplay.Background    = isReplay     ? accentBrush : itemBg;

        // 활성 탭: 흰색 텍스트, 비활성: PrimaryText
        TabTimelineIcon.Foreground  = isTimeline   ? Brushes.White : primaryText;
        TabTimelineText.Foreground  = isTimeline   ? Brushes.White : primaryText;
        TabBottleneckIcon.Foreground = isBottleneck ? Brushes.White : primaryText;
        TabBottleneckText.Foreground = isBottleneck ? Brushes.White : primaryText;
        TabReplayIcon.Foreground    = isReplay     ? Brushes.White : primaryText;
        TabReplayText.Foreground    = isReplay     ? Brushes.White : primaryText;

        TimelineScroller.Visibility  = isTimeline   ? Visibility.Visible : Visibility.Collapsed;
        BottleneckScroller.Visibility = isBottleneck ? Visibility.Visible : Visibility.Collapsed;
        ReplayScroller.Visibility    = isReplay     ? Visibility.Visible : Visibility.Collapsed;
        DetailPanel.Visibility = isTimeline && DetailPanel.Tag != null
            ? Visibility.Visible : Visibility.Collapsed;
    }

    // ─── 병목 분석 데이터 수집 ──────────────────────────────────────

    private record WaterfallEntry(string Label, long StartMs, long DurationMs, string Type, bool IsBottleneck = false);

    private void CollectBottleneckData(AgentEvent evt)
    {
        var currentMs = (long)(evt.Timestamp - _startTime).TotalMilliseconds;

        // 워터폴: LLM Thinking과 ToolResult (소요시간이 있는 이벤트)
        if (evt.Type == AgentEventType.Thinking && evt.Iteration > 0)
        {
            // LLM 호출 시작 기록 (종료 시점은 다음 ToolCall/Complete 이벤트에서 계산)
            _lastEventMs = currentMs;
        }
        else if (evt.Type == AgentEventType.ToolCall)
        {
            // 이전 LLM 사고 시간 = 현재 - 마지막 이벤트
            if (_lastEventMs > 0)
            {
                var llmDuration = currentMs - _lastEventMs;
                if (llmDuration > 100) // 100ms 미만은 노이즈
                {
                    _waterfallEntries.Add(new WaterfallEntry(
                        $"LLM #{evt.Iteration}", _lastEventMs, llmDuration, "llm"));
                }
            }
            _lastEventMs = currentMs;
        }
        else if (evt.Type == AgentEventType.ToolResult && evt.ElapsedMs > 0)
        {
            // 도구 실행 시간
            var toolStart = currentMs - evt.ElapsedMs;
            _waterfallEntries.Add(new WaterfallEntry(
                evt.ToolName, toolStart, evt.ElapsedMs, "tool"));

            // 도구별 누적
            var key = evt.ToolName;
            _toolTimeAccum[key] = _toolTimeAccum.GetValueOrDefault(key) + evt.ElapsedMs;

            _lastEventMs = currentMs;
        }
        else if (evt.Type == AgentEventType.Complete && _lastEventMs > 0)
        {
            // 마지막 LLM 사고 시간
            var llmDuration = currentMs - _lastEventMs;
            if (llmDuration > 100)
            {
                _waterfallEntries.Add(new WaterfallEntry(
                    $"LLM (마무리)", _lastEventMs, llmDuration, "llm"));
            }
        }

        // 토큰 추세
        if ((evt.InputTokens > 0 || evt.OutputTokens > 0) && evt.Iteration > 0)
        {
            // 같은 반복의 기존 항목이 있으면 업데이트
            var idx = _tokenTrend.FindIndex(t => t.Iteration == evt.Iteration);
            if (idx >= 0)
            {
                var old = _tokenTrend[idx];
                _tokenTrend[idx] = (evt.Iteration,
                    old.Input + evt.InputTokens,
                    old.Output + evt.OutputTokens);
            }
            else
            {
                _tokenTrend.Add((evt.Iteration, evt.InputTokens, evt.OutputTokens));
            }
        }
    }

    // ─── Phase 18-B: 리플레이 탭 ──────────────────────────────────────────

    private ReplaySessionInfo? _selectedReplaySession;

    /// <summary>저장된 세션 목록을 리플레이 패널에 로드합니다.</summary>
    private void LoadReplaySessions()
    {
        _replayVm.LoadSessions();
        ReplaySessionList.Children.Clear();

        var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
        var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.LightGray;
        var itemHover = TryFindResource("ItemHoverBackground") as Brush
                        ?? new SolidColorBrush(Color.FromArgb(0x18, 0xFF, 0xFF, 0xFF));

        if (_replayVm.Sessions.Count == 0)
        {
            ReplaySessionList.Children.Add(new TextBlock
            {
                Text = "저장된 세션이 없습니다.",
                FontSize = 11,
                Foreground = secondaryText,
                Margin = new Thickness(4, 2, 0, 2),
            });
            return;
        }

        foreach (var session in _replayVm.Sessions)
        {
            var row = new Border
            {
                CornerRadius = new CornerRadius(4),
                Padding = new Thickness(8, 4, 8, 4),
                Margin = new Thickness(0, 1, 0, 1),
                Cursor = System.Windows.Input.Cursors.Hand,
                Tag = session,
            };
            row.Child = new TextBlock
            {
                Text = $"{session.CreatedAt:MM-dd HH:mm}  [{session.SessionId[..Math.Min(8, session.SessionId.Length)]}]  {session.FileSizeBytes / 1024}KB",
                FontSize = 11,
                Foreground = primaryText,
            };
            row.MouseEnter  += (_, _) => row.Background = itemHover;
            row.MouseLeave  += (_, _) => row.Background = null;
            row.MouseLeftButtonUp += (_, _) =>
            {
                _selectedReplaySession = session;
                _replayVm.SelectedSession = session;
                // 선택 강조
                foreach (Border child in ReplaySessionList.Children.OfType<Border>())
                    child.BorderThickness = new Thickness(0);
                row.BorderBrush = TryFindResource("AccentColor") as Brush;
                row.BorderThickness = new Thickness(1);
            };
            ReplaySessionList.Children.Add(row);
        }
    }

    private void BtnReplayStart_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        if (_replayVm.SelectedSession == null) return;

        ReplayEventPanel.Children.Clear();
        ReplayProgress.Value = 0;

        // ReplayEventReceived 이벤트 구독 (중복 방지)
        _replayVm.ReplayEventReceived -= OnReplayEventReceived;
        _replayVm.ReplayEventReceived += OnReplayEventReceived;

        _ = _replayVm.StartReplayAsync();
    }

    private void OnReplayEventReceived(ReplayEventItem item)
    {
        Dispatcher.Invoke(() =>
        {
            var node = BuildReplayEventRow(item);
            ReplayEventPanel.Children.Add(node);
            ReplayEventScroll.ScrollToEnd();

            // 진행 표시
            if (_replayVm.ProgressMax > 0)
                ReplayProgress.Value = (double)_replayVm.ProgressValue / _replayVm.ProgressMax * 100;
        });
    }

    private void BtnReplayStop_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
        => _replayVm.StopReplay();

    private void ReplaySpeedSlider_Changed(object sender, System.Windows.RoutedPropertyChangedEventArgs<double> e)
    {
        _replayVm.ReplaySpeedMs = (int)e.NewValue;
        if (ReplaySpeedLabel != null)
            ReplaySpeedLabel.Text = $"{(int)e.NewValue}ms";
    }

    /// <summary>리플레이 이벤트 하나를 작은 행 UI로 빌드합니다.</summary>
    private Border BuildReplayEventRow(ReplayEventItem item)
    {
        var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
        var color = item.Record.Type switch
        {
            AgentEventLogType.ToolRequest    => Color.FromRgb(0x60, 0xA5, 0xFA),
            AgentEventLogType.ToolResult     => Color.FromRgb(0x34, 0xD3, 0x99),
            AgentEventLogType.Error          => Color.FromRgb(0xF8, 0x71, 0x71),
            AgentEventLogType.SessionEnd     => Color.FromRgb(0x34, 0xD3, 0x99),
            AgentEventLogType.AssistantMessage => Color.FromRgb(0xFB, 0xBF, 0x24),
            _                                => Color.FromRgb(0x94, 0xA3, 0xB8),
        };
        var icon = item.Icon;
        var summary = item.Record.Payload ?? item.TypeLabel;

        var grid = new System.Windows.Controls.Grid();
        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(20) });
        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(8, GridUnitType.Star) });
        grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

        var iconTb = new TextBlock
        {
            Text = icon,
            FontFamily = ThemeResourceHelper.SegoeMdl2,
            FontSize = 10,
            Foreground = new SolidColorBrush(color),
            VerticalAlignment = VerticalAlignment.Center,
        };
        Grid.SetColumn(iconTb, 0);
        grid.Children.Add(iconTb);

        var summaryTb = new TextBlock
        {
            Text = summary.Length > 60 ? summary[..57] + "…" : summary,
            FontSize = 10.5,
            Foreground = primaryText,
            TextTrimming = TextTrimming.CharacterEllipsis,
            VerticalAlignment = VerticalAlignment.Center,
            Margin = new Thickness(4, 0, 4, 0),
        };
        Grid.SetColumn(summaryTb, 1);
        grid.Children.Add(summaryTb);

        var timeTb = new TextBlock
        {
            Text = item.Record.Timestamp.ToString("HH:mm:ss"),
            FontSize = 9,
            Foreground = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray,
            VerticalAlignment = VerticalAlignment.Center,
        };
        Grid.SetColumn(timeTb, 2);
        grid.Children.Add(timeTb);

        return new Border
        {
            Child = grid,
            Padding = new Thickness(4, 2, 4, 2),
            Margin = new Thickness(0, 1, 0, 1),
        };
    }

}
