/**
 * TokenUsageDisplay - Compact token usage display with detailed breakdown on hover.
 * Shows total tokens with an info icon that reveals a popover with:
 * - Input tokens breakdown
 * - Cache read/write tokens
 * - Output tokens
 * - Optional model information
 */

import React, { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';

import { COLOR_TEXT_MUTED, COLOR_TEXT_SECONDARY } from '@renderer/constants/cssVariables';
import { formatCostUsd } from '@shared/utils/costFormatting';
import { getModelColorClass } from '@shared/utils/modelParser';
import {
  formatTokensCompact as formatTokens,
  formatTokensDetailed,
} from '@shared/utils/tokenFormatting';
import { ChevronRight, Info } from 'lucide-react';

import type { ClaudeMdStats } from '@renderer/types/claudeMd';
import type { ContextStats } from '@renderer/types/contextInjection';
import type { ModelInfo } from '@shared/utils/modelParser';

interface TokenUsageDisplayProps {
  /** Input tokens count */
  inputTokens: number;
  /** Output tokens count */
  outputTokens: number;
  /** Cache read tokens count */
  cacheReadTokens: number;
  /** Cache creation/write tokens count */
  cacheCreationTokens: number;
  /** Optional model name for display */
  modelName?: string;
  /** Optional model family for color styling */
  modelFamily?: ModelInfo['family'];
  /** Size variant - 'sm' for compact, 'md' for slightly larger */
  size?: 'sm' | 'md';
  /** Optional CLAUDE.md injection statistics (deprecated, use contextStats) */
  claudeMdStats?: ClaudeMdStats;
  /** Optional unified context statistics */
  contextStats?: ContextStats;
  /** Phase number for this AI group */
  phaseNumber?: number;
  /** Total number of phases in the session */
  totalPhases?: number;
  /** Optional USD cost for this usage */
  costUsd?: number;
}

/**
 * Expandable section showing session-wide context breakdown.
 * Shows accumulated totals for CLAUDE.md, mentioned files, tool outputs, and thinking+text.
 */
const SessionContextSection = ({
  contextStats,
  totalInputTokens,
}: Readonly<{
  contextStats: ContextStats;
  totalInputTokens: number;
}>): React.JSX.Element => {
  const [expanded, setExpanded] = useState(false);

  const { tokensByCategory } = contextStats;

  // contextStats.totalEstimatedTokens already includes all categories (CLAUDE.md, @files,
  // tool outputs, thinking+text, task coordination, user messages) - no manual adjustment needed.
  // Visible Context is always shown as a share of prompt-side input tokens so this section
  // stays aligned with the unified context contract instead of silently switching semantics.
  const contextPercent =
    totalInputTokens > 0
      ? Math.min((contextStats.totalEstimatedTokens / totalInputTokens) * 100, 100).toFixed(1)
      : '0.0';

  // Count accumulated injections by category
  const claudeMdCount = contextStats.accumulatedInjections.filter(
    (inj) => inj.category === 'claude-md'
  ).length;
  const mentionedFilesCount = contextStats.accumulatedInjections.filter(
    (inj) => inj.category === 'mentioned-file'
  ).length;
  const toolOutputsCount = contextStats.accumulatedInjections.filter(
    (inj) => inj.category === 'tool-output'
  ).length;
  const taskCoordinationCount = contextStats.accumulatedInjections.filter(
    (inj) => inj.category === 'task-coordination'
  ).length;
  const userMessagesCount = contextStats.accumulatedInjections.filter(
    (inj) => inj.category === 'user-message'
  ).length;

  // Calculate percentages for each category (relative to total input tokens)
  const claudeMdPercent =
    totalInputTokens > 0
      ? Math.min((tokensByCategory.claudeMd / totalInputTokens) * 100, 100).toFixed(1)
      : '0.0';
  const mentionedFilesPercent =
    totalInputTokens > 0
      ? Math.min((tokensByCategory.mentionedFiles / totalInputTokens) * 100, 100).toFixed(1)
      : '0.0';
  const toolOutputsPercent =
    totalInputTokens > 0
      ? Math.min((tokensByCategory.toolOutputs / totalInputTokens) * 100, 100).toFixed(1)
      : '0.0';
  const thinkingTextPercent =
    totalInputTokens > 0
      ? Math.min((tokensByCategory.thinkingText / totalInputTokens) * 100, 100).toFixed(1)
      : '0.0';
  const taskCoordinationPercent =
    totalInputTokens > 0
      ? Math.min((tokensByCategory.taskCoordination / totalInputTokens) * 100, 100).toFixed(1)
      : '0.0';
  const userMessagesPercent =
    totalInputTokens > 0
      ? Math.min((tokensByCategory.userMessages / totalInputTokens) * 100, 100).toFixed(1)
      : '0.0';

  return (
    <div className="mt-1">
      {/* Divider */}
      <div className="my-1" style={{ borderTop: '1px solid var(--color-border-subtle)' }} />

      {/* Header - clickable to expand */}
      <div
        role="button"
        tabIndex={0}
        className="-mx-1 flex cursor-pointer items-center justify-between gap-3 rounded px-1 py-0.5 transition-colors hover:bg-white/5"
        onClick={() => setExpanded(!expanded)}
        onKeyDown={(e) => {
          if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            setExpanded(!expanded);
          }
        }}
      >
        <div className="flex items-center gap-1" style={{ color: COLOR_TEXT_MUTED }}>
          <ChevronRight
            className={`size-3 shrink-0 transition-transform duration-150 ${expanded ? 'rotate-90' : ''}`}
          />
          <span className="whitespace-nowrap text-[10px]">Visible Context</span>
        </div>
        <span
          className="whitespace-nowrap text-[10px] tabular-nums"
          style={{ color: COLOR_TEXT_MUTED }}
        >
          {formatTokens(contextStats.totalEstimatedTokens)} ({contextPercent}% of prompt input)
        </span>
      </div>

      {/* Expanded details */}
      {expanded && (
        <div className="mt-1 space-y-1.5 pl-4">
          {/* CLAUDE.md */}
          {tokensByCategory.claudeMd > 0 && (
            <div className="flex items-center justify-between text-[10px]">
              <span style={{ color: COLOR_TEXT_MUTED }}>
                CLAUDE.md <span className="opacity-60">×{claudeMdCount}</span>
              </span>
              <span className="tabular-nums" style={{ color: COLOR_TEXT_SECONDARY }}>
                {formatTokens(tokensByCategory.claudeMd)}{' '}
                <span className="opacity-60">({claudeMdPercent}%)</span>
              </span>
            </div>
          )}

          {/* Mentioned Files */}
          {tokensByCategory.mentionedFiles > 0 && (
            <div className="flex items-center justify-between text-[10px]">
              <span style={{ color: COLOR_TEXT_MUTED }}>
                @files <span className="opacity-60">×{mentionedFilesCount}</span>
              </span>
              <span className="tabular-nums" style={{ color: COLOR_TEXT_SECONDARY }}>
                {formatTokens(tokensByCategory.mentionedFiles)}{' '}
                <span className="opacity-60">({mentionedFilesPercent}%)</span>
              </span>
            </div>
          )}

          {/* Tool Outputs */}
          {tokensByCategory.toolOutputs > 0 && (
            <div className="flex items-center justify-between text-[10px]">
              <span style={{ color: COLOR_TEXT_MUTED }}>
                工具输出 <span className="opacity-60">×{toolOutputsCount}</span>
              </span>
              <span className="tabular-nums" style={{ color: COLOR_TEXT_SECONDARY }}>
                {formatTokens(tokensByCategory.toolOutputs)}{' '}
                <span className="opacity-60">({toolOutputsPercent}%)</span>
              </span>
            </div>
          )}

          {/* Task Coordination */}
          {tokensByCategory.taskCoordination > 0 && (
            <div className="flex items-center justify-between text-[10px]">
              <span style={{ color: COLOR_TEXT_MUTED }}>
                任务协作 <span className="opacity-60">×{taskCoordinationCount}</span>
              </span>
              <span className="tabular-nums" style={{ color: COLOR_TEXT_SECONDARY }}>
                {formatTokens(tokensByCategory.taskCoordination)}{' '}
                <span className="opacity-60">({taskCoordinationPercent}%)</span>
              </span>
            </div>
          )}

          {/* User Messages */}
          {tokensByCategory.userMessages > 0 && (
            <div className="flex items-center justify-between text-[10px]">
              <span style={{ color: COLOR_TEXT_MUTED }}>
                用户消息 <span className="opacity-60">×{userMessagesCount}</span>
              </span>
              <span className="tabular-nums" style={{ color: COLOR_TEXT_SECONDARY }}>
                {formatTokens(tokensByCategory.userMessages)}{' '}
                <span className="opacity-60">({userMessagesPercent}%)</span>
              </span>
            </div>
          )}

          {/* Thinking + Text */}
          {tokensByCategory.thinkingText > 0 && (
            <div className="flex items-center justify-between text-[10px]">
              <span style={{ color: COLOR_TEXT_MUTED }}>思考 + 文本</span>
              <span className="tabular-nums" style={{ color: COLOR_TEXT_SECONDARY }}>
                {formatTokens(tokensByCategory.thinkingText)}{' '}
                <span className="opacity-60">({thinkingTextPercent}%)</span>
              </span>
            </div>
          )}

          {/* Hint about session scope */}
          <div
            className="pt-0.5 text-[9px] italic"
            style={{ color: COLOR_TEXT_MUTED, opacity: 0.7 }}
          >
            按整个会话累计，已去重
          </div>
        </div>
      )}
    </div>
  );
};

export const TokenUsageDisplay = ({
  inputTokens,
  outputTokens,
  cacheReadTokens,
  cacheCreationTokens,
  modelName,
  modelFamily,
  size = 'sm',
  claudeMdStats,
  contextStats,
  phaseNumber,
  totalPhases,
  costUsd,
}: Readonly<TokenUsageDisplayProps>): React.JSX.Element => {
  const totalTokens = inputTokens + cacheReadTokens + cacheCreationTokens + outputTokens;
  // Total prompt-side tokens only (without output) - used as denominator for visible context %
  const totalInputTokens = inputTokens + cacheReadTokens + cacheCreationTokens;
  const formattedTotal = formatTokens(totalTokens);

  // Size-based classes
  const textSize = size === 'sm' ? 'text-xs' : 'text-sm';
  const iconSize = size === 'sm' ? 'w-3 h-3' : 'w-3.5 h-3.5';

  // Model color based on family
  const modelColorClass = modelFamily ? getModelColorClass(modelFamily) : '';

  // Use React state for hover instead of CSS group-hover to avoid
  // interference with parent components that also use the 'group' class
  const [showPopover, setShowPopover] = useState(false);
  const [popoverStyle, setPopoverStyle] = useState<React.CSSProperties>({});
  const [arrowStyle, setArrowStyle] = useState<React.CSSProperties>({});
  const containerRef = useRef<HTMLDivElement>(null);
  const popoverRef = useRef<HTMLDivElement>(null);
  const hideTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const isDraggingRef = useRef(false);

  // Clear timeout helper
  const clearHideTimeout = (): void => {
    if (hideTimeoutRef.current) {
      clearTimeout(hideTimeoutRef.current);
      hideTimeoutRef.current = null;
    }
  };

  // Show popover immediately, clear any pending hide
  const handleMouseEnter = (): void => {
    clearHideTimeout();
    setShowPopover(true);
  };

  // Hide popover with delay (allows mouse to move to popover)
  const handleMouseLeave = (): void => {
    // Don't hide while dragging inside the popover
    if (isDraggingRef.current) return;
    clearHideTimeout();
    hideTimeoutRef.current = setTimeout(() => {
      setShowPopover(false);
    }, 150);
  };

  // Cleanup timeout on unmount and close on scroll
  useEffect(() => {
    return () => clearHideTimeout();
  }, []);

  // Close popover on scroll
  useEffect(() => {
    if (!showPopover) return;

    const handleScroll = (e: Event): void => {
      // Don't close if scrolling inside the popover
      if (popoverRef.current && e.target instanceof Node && popoverRef.current.contains(e.target)) {
        return;
      }
      setShowPopover(false);
    };

    window.addEventListener('scroll', handleScroll, true);
    return () => window.removeEventListener('scroll', handleScroll, true);
  }, [showPopover]);

  // Calculate popover position based on trigger element
  useEffect(() => {
    if (showPopover && containerRef.current) {
      const rect = containerRef.current.getBoundingClientRect();
      const viewportWidth = window.innerWidth;
      const viewportHeight = window.innerHeight;
      const popoverWidth = 220;
      const margin = 12;

      // Determine if popover should open left or right
      const openLeft = rect.left + popoverWidth > viewportWidth - 20;

      // Determine if popover should open above or below
      const spaceBelow = viewportHeight - rect.bottom - margin;
      const spaceAbove = rect.top - margin;
      const openAbove = spaceBelow < 200 && spaceAbove > spaceBelow;

      const maxHeight = Math.max(openAbove ? spaceAbove : spaceBelow, 120) - 8;

      queueMicrotask(() => {
        setPopoverStyle({
          position: 'fixed',
          ...(openAbove ? { bottom: viewportHeight - rect.top + 4 } : { top: rect.bottom + 4 }),
          left: openLeft ? rect.right - popoverWidth : rect.left,
          minWidth: 200,
          maxWidth: 280,
          maxHeight,
          overflowY: 'auto',
          zIndex: 99999,
        });

        setArrowStyle({
          position: 'absolute',
          ...(openAbove
            ? {
                bottom: -4,
                borderRight: '1px solid var(--color-border)',
                borderBottom: '1px solid var(--color-border)',
                borderLeft: 'none',
                borderTop: 'none',
              }
            : {
                top: -4,
                borderLeft: '1px solid var(--color-border)',
                borderTop: '1px solid var(--color-border)',
                borderRight: 'none',
                borderBottom: 'none',
              }),
          [openLeft ? 'right' : 'left']: 8,
          width: 8,
          height: 8,
          transform: 'rotate(45deg)',
          backgroundColor: 'var(--color-surface-raised)',
        });
      });
    }
  }, [showPopover]);

  return (
    <div
      className={`inline-flex items-center gap-1 ${textSize}`}
      style={{ color: COLOR_TEXT_MUTED }}
    >
      <span className="font-medium">{formattedTotal}</span>
      {totalPhases && totalPhases > 1 && phaseNumber && (
        <span
          className="rounded px-1 py-0.5 text-[10px]"
          style={{ backgroundColor: 'rgba(99, 102, 241, 0.15)', color: '#818cf8' }}
        >
          Phase {phaseNumber}/{totalPhases}
        </span>
      )}
      <div
        ref={containerRef}
        role="button"
        tabIndex={0}
        className="relative"
        onMouseEnter={handleMouseEnter}
        onMouseLeave={handleMouseLeave}
        onFocus={handleMouseEnter}
        onBlur={(e) => {
          // Don't close if focus moved into the popover
          if (popoverRef.current?.contains(e.relatedTarget as Node)) return;
          handleMouseLeave();
        }}
        onKeyDown={(e) => {
          if (e.key === 'Enter' || e.key === ' ') {
            e.preventDefault();
            setShowPopover(!showPopover);
          }
        }}
        aria-expanded={showPopover}
        aria-haspopup="true"
      >
        <Info
          className={`${iconSize} cursor-help transition-colors`}
          style={{ color: COLOR_TEXT_MUTED }}
        />
        {/* Popover - rendered via Portal to escape stacking context */}
        {showPopover &&
          createPortal(
            // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events -- tooltip uses mouse handlers for hover/drag behavior, not interactive
            <div
              ref={popoverRef}
              role="tooltip"
              className="rounded-lg p-3 shadow-xl"
              style={{
                ...popoverStyle,
                backgroundColor: 'var(--color-surface-raised)',
                border: '1px solid var(--color-border)',
                boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.3)',
              }}
              onMouseEnter={handleMouseEnter}
              onMouseLeave={handleMouseLeave}
              onMouseDown={(e) => {
                e.stopPropagation();
                isDraggingRef.current = true;
                const handleMouseUp = (): void => {
                  isDraggingRef.current = false;
                  document.removeEventListener('mouseup', handleMouseUp);
                };
                document.addEventListener('mouseup', handleMouseUp);
              }}
              onClick={(e) => e.stopPropagation()}
            >
              {/* Arrow pointer */}
              <div style={arrowStyle} />

              <div className="space-y-2 text-xs">
                {/* Input Tokens */}
                <div className="flex items-center justify-between">
                  <span style={{ color: COLOR_TEXT_MUTED }}>Input Tokens</span>
                  <span
                    className="font-medium tabular-nums"
                    style={{ color: COLOR_TEXT_SECONDARY }}
                  >
                    {formatTokensDetailed(inputTokens)}
                  </span>
                </div>

                {/* Cache Read */}
                <div className="flex items-center justify-between">
                  <span style={{ color: COLOR_TEXT_MUTED }}>Cache Read</span>
                  <span
                    className="font-medium tabular-nums"
                    style={{ color: COLOR_TEXT_SECONDARY }}
                  >
                    {formatTokensDetailed(cacheReadTokens)}
                  </span>
                </div>

                {/* Cache Write/Creation */}
                <div className="flex items-center justify-between">
                  <span style={{ color: COLOR_TEXT_MUTED }}>Cache Write</span>
                  <span
                    className="font-medium tabular-nums"
                    style={{ color: COLOR_TEXT_SECONDARY }}
                  >
                    {formatTokensDetailed(cacheCreationTokens)}
                  </span>
                </div>

                {/* Output Tokens */}
                <div className="flex items-center justify-between">
                  <span style={{ color: COLOR_TEXT_MUTED }}>输出 Token</span>
                  <span
                    className="font-medium tabular-nums"
                    style={{ color: COLOR_TEXT_SECONDARY }}
                  >
                    {formatTokensDetailed(outputTokens)}
                  </span>
                </div>

                {/* Divider before Total */}
                <div
                  className="my-1"
                  style={{ borderTop: '1px solid var(--color-border-subtle)' }}
                />

                {/* Total */}
                <div className="flex items-center justify-between">
                  <span className="font-medium" style={{ color: COLOR_TEXT_SECONDARY }}>
                    Total
                  </span>
                  <span
                    className="font-medium tabular-nums"
                    style={{ color: 'var(--color-text-primary, var(--color-text))' }}
                  >
                    {formatTokensDetailed(totalTokens)}
                  </span>
                </div>

                {/* Cost (USD) - if available */}
                {costUsd !== undefined && costUsd > 0 && (
                  <div className="mt-1 flex items-center justify-between text-[10px]">
                    <span style={{ color: COLOR_TEXT_SECONDARY }}>Cost (USD)</span>
                    <span
                      className="tabular-nums"
                      style={{ color: 'var(--color-text-primary, var(--color-text))' }}
                    >
                      {formatCostUsd(costUsd)}
                    </span>
                  </div>
                )}

                {/* Visible Context Breakdown - expandable section */}
                {contextStats && contextStats.totalEstimatedTokens > 0 && (
                  <SessionContextSection
                    contextStats={contextStats}
                    totalInputTokens={totalInputTokens}
                  />
                )}

                {/* CLAUDE.md Breakdown - fallback when contextStats not provided (deprecated) */}
                {!contextStats && claudeMdStats && (
                  <div
                    className="mt-1 flex items-center justify-between text-[10px]"
                    style={{ color: COLOR_TEXT_MUTED }}
                  >
                    <span className="whitespace-nowrap italic">
                      incl. CLAUDE.md ×{claudeMdStats.accumulatedCount}
                    </span>
                    <span className="tabular-nums">
                      {totalInputTokens > 0
                        ? ((claudeMdStats.totalEstimatedTokens / totalInputTokens) * 100).toFixed(1)
                        : '0.0'}
                      %
                    </span>
                  </div>
                )}

                {/* Model Info (optional) */}
                {modelName && (
                  <>
                    <div
                      className="my-1"
                      style={{ borderTop: '1px solid var(--color-border-subtle)' }}
                    />
                    <div className="flex items-center justify-between">
                      <span style={{ color: COLOR_TEXT_MUTED }}>Model</span>
                      <span
                        className={`font-medium ${modelColorClass}`}
                        style={!modelColorClass ? { color: COLOR_TEXT_SECONDARY } : {}}
                      >
                        {modelName}
                      </span>
                    </div>
                  </>
                )}
              </div>
            </div>,
            document.body
          )}
      </div>
    </div>
  );
};
