/**
 * Chat Message Component
 */

import {
  User,
  Bot,
  Copy,
  Check,
  Wrench,
  ChevronDown,
  ChevronRight,
  Clock,
  AlertCircle,
  CheckCircle2,
  Loader2,
  GitCompare,
  Coins,
} from 'lucide-react';
import { motion, AnimatePresence } from 'framer-motion';
import { useState, forwardRef } from 'react';
import { cn } from '../utils/cn';
import { fadeInUp, smoothTransition } from '../utils/animations';
import { getAgentDisplayName } from '../utils/agent';
import { Markdown } from './Markdown';
import { FileMentionText } from './FileMentionTag';
import type { Message, ToolStatus, ToolMessagePart, QuestionMessagePart, PermissionMessagePart, FileDiffInfo } from '../api/types.js';
import { AskUserQuestion } from './AskUserQuestion.js';
import { PermissionRequestInline } from './PermissionRequestInline.js';

interface ChatMessageProps {
  message: Message;
  /** 是否为流式输出中（显示打字光标） */
  isStreaming?: boolean;
  /** 回答问题的回调（用于 ask_user_question 工具） */
  onAnswerQuestion?: (questionPartId: string, answers: string[]) => void;
  /** 查看文件 Diff 的回调 */
  onViewDiff?: (diff: FileDiffInfo) => void;
  /** 允许权限请求的回调 */
  onAllowPermission?: (requestId: string, remember: boolean) => void;
  /** 拒绝权限请求的回调 */
  onDenyPermission?: (requestId: string, remember: boolean) => void;
}

// 格式化 Token 数量
const formatTokens = (tokens: number): string => {
  if (tokens >= 1000000) {
    return `${(tokens / 1000000).toFixed(2)}M`;
  }
  if (tokens >= 1000) {
    return `${(tokens / 1000).toFixed(1)}k`;
  }
  return `${tokens}`;
};

export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
  ({ message, isStreaming = false, onAnswerQuestion, onViewDiff, onAllowPermission, onDenyPermission }, ref) => {
    const isUser = message.role === 'user';
    const [copied, setCopied] = useState(false);

    // Token 信息
    const hasTokenInfo = !isUser && message.metadata?.inputTokens !== undefined;
    const inputTokens = message.metadata?.inputTokens ?? 0;
    const outputTokens = message.metadata?.outputTokens ?? 0;
    const totalTokens = message.metadata?.totalTokens ?? (inputTokens + outputTokens);

    const handleCopy = async () => {
      await navigator.clipboard.writeText(message.content ?? '');
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    };

    // 渲染消息内容 - 使用 parts 保持原始顺序
    const renderContent = () => {
      // 优先使用 parts 数组（保持原始顺序）
      if (message.parts && message.parts.length > 0) {
        // 查找最后一个文本 part 的索引（用于显示打字光标）
        let lastTextPartIndex = -1;
        if (isStreaming) {
          for (let i = message.parts.length - 1; i >= 0; i--) {
            if (message.parts[i].type === 'text') {
              lastTextPartIndex = i;
              break;
            }
          }
        }

        return (
          <div className="message-content text-fg-secondary space-y-3">
            {message.parts.map((part, index) => {
              switch (part.type) {
                case 'text':
                  if (!part.text && index !== lastTextPartIndex) return null;
                  return isUser ? (
                    <div key={part.id}>
                      <FileMentionText text={part.text} />
                    </div>
                  ) : (
                    <div key={part.id}>
                      <Markdown content={part.text} />
                      {/* 流式输出时在最后一个文本末尾显示打字光标 */}
                      {isStreaming && index === lastTextPartIndex && (
                        <motion.span
                          animate={{ opacity: [1, 0] }}
                          transition={{ duration: 0.8, repeat: Infinity, repeatType: 'reverse' }}
                          className="inline-block w-2 h-4 bg-primary-400 ml-1 rounded-sm align-middle"
                        />
                      )}
                    </div>
                  );
                case 'tool':
                  return <ToolPartItem key={part.id} part={part} onViewDiff={onViewDiff} />;
                case 'question': {
                  // 问题组件：即使在流式输出时也允许用户回答（除非已回答）
                  const questionPart = part as QuestionMessagePart;
                  return (
                    <AskUserQuestion
                      key={part.id}
                      part={questionPart}
                      onAnswer={
                        onAnswerQuestion
                          ? (answers) => onAnswerQuestion(part.id, answers)
                          : undefined
                      }
                      disabled={questionPart.answered}
                    />
                  );
                }
                case 'reasoning':
                  return (
                    <div key={part.id} className="text-fg-muted italic border-l-2 border-line pl-3">
                      {part.text}
                    </div>
                  );
                case 'permission': {
                  // 权限请求组件：内联显示，不阻断用户操作
                  const permissionPart = part as PermissionMessagePart;
                  return (
                    <PermissionRequestInline
                      key={part.id}
                      part={permissionPart}
                      onAllow={onAllowPermission || (() => {})}
                      onDeny={onDenyPermission || (() => {})}
                      disabled={permissionPart.handled}
                    />
                  );
                }
                default:
                  return null;
              }
            })}
          </div>
        );
      }

      // 回退：使用 content 字段（无 parts 时）
      return (
        <div className="message-content text-fg-secondary">
          {isUser ? (
            <div>
              <FileMentionText text={message.content ?? ''} />
            </div>
          ) : (
            <Markdown content={message.content ?? ''} />
          )}
        </div>
      );
    };

    return (
      <motion.div
        ref={ref}
        variants={fadeInUp}
        initial="initial"
        animate="animate"
        exit="exit"
        transition={smoothTransition}
        className={cn(
          'group flex gap-4 p-4 rounded-lg',
          isUser ? 'bg-surface-subtle' : 'bg-surface-subtle/50'
        )}
      >
        <div
          className={cn(
            'w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 text-white',
            isUser ? 'bg-primary-600' : 'bg-green-600'
          )}
        >
          {isUser ? <User size={18} /> : <Bot size={18} />}
        </div>
        <div className="flex-1 min-w-0 overflow-hidden">
          <div className="flex items-center justify-between mb-1">
            <span className="text-sm text-fg-muted">
              {isUser ? 'You' : getAgentDisplayName(message.metadata?.agentName)}
            </span>
            <button
              onClick={handleCopy}
              className="opacity-0 group-hover:opacity-100 p-1 rounded text-fg-subtle hover:text-fg-muted hover:bg-surface-muted transition-all"
              title="Copy message"
            >
              {copied ? <Check size={14} className="text-green-500" /> : <Copy size={14} />}
            </button>
          </div>
          {renderContent()}
          {/* Token 统计显示（仅 AI 消息，非流式输出时） */}
          {hasTokenInfo && !isStreaming && totalTokens > 0 && (
            <div className="mt-2 pt-2 border-t border-line/50 flex items-center gap-3 text-xs text-fg-subtle">
              <span className="flex items-center gap-1" title="Token 消耗">
                <Coins size={12} className="text-fg-muted" />
                <span>{formatTokens(totalTokens)}</span>
              </span>
              <span className="text-fg-muted/40">|</span>
              <span title="输入 Token">
                ↓ {formatTokens(inputTokens)}
              </span>
              <span title="输出 Token">
                ↑ {formatTokens(outputTokens)}
              </span>
            </div>
          )}
        </div>
      </motion.div>
    );
  }
);

interface StreamingMessageProps {
  content: string;
  /** 当前 Agent 名称 */
  agentName?: string;
}

export function StreamingMessage({ content, agentName }: StreamingMessageProps) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 10 }}
      animate={{ opacity: 1, y: 0 }}
      transition={smoothTransition}
      className="flex gap-4 p-4 rounded-lg bg-surface-subtle/50"
    >
      <div className="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 bg-green-600 text-white">
        <Bot size={18} />
      </div>
      <div className="flex-1 min-w-0 overflow-hidden">
        <div className="text-sm text-fg-muted mb-1">{getAgentDisplayName(agentName)}</div>
        <div className="message-content text-fg-secondary">
          <Markdown content={content} />
          <motion.span
            animate={{ opacity: [1, 0] }}
            transition={{ duration: 0.8, repeat: Infinity, repeatType: 'reverse' }}
            className="inline-block w-2 h-4 bg-primary-400 ml-1 rounded-sm align-middle"
          />
        </div>
      </div>
    </motion.div>
  );
}

interface TypingIndicatorProps {
  /** 当前 Agent 名称 */
  agentName?: string;
}

export function TypingIndicator({ agentName }: TypingIndicatorProps) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 10 }}
      animate={{ opacity: 1, y: 0 }}
      transition={smoothTransition}
      className="flex gap-4 p-4 rounded-lg bg-surface-subtle/50"
    >
      <div className="w-8 h-8 rounded-full flex items-center justify-center flex-shrink-0 bg-green-600 text-white">
        <Bot size={18} />
      </div>
      <div className="flex-1">
        <div className="text-sm text-fg-muted mb-1">{getAgentDisplayName(agentName)}</div>
        <div className="flex items-center gap-1 h-6">
          {[0, 1, 2].map((i) => (
            <motion.span
              key={i}
              animate={{ y: [0, -4, 0] }}
              transition={{
                duration: 0.6,
                repeat: Infinity,
                delay: i * 0.15,
              }}
              className="w-2 h-2 rounded-full bg-fg-muted"
            />
          ))}
        </div>
      </div>
    </motion.div>
  );
}

// ============ 工具调用显示组件 ============

/**
 * 单个工具 Part 项（用于 parts 数组渲染）
 */
interface ToolPartItemProps {
  part: ToolMessagePart;
  /** 查看文件 Diff 的回调 */
  onViewDiff?: (diff: FileDiffInfo) => void;
}

function ToolPartItem({ part, onViewDiff }: ToolPartItemProps) {
  const [expanded, setExpanded] = useState(false);
  const hasDetails =
    Object.keys(part.arguments).length > 0 ||
    part.result !== undefined ||
    part.error !== undefined;

  // 判断是否为文件操作工具且有 diff 数据
  const isFileOperation = part.toolName === 'write_file' || part.toolName === 'edit_file';
  const hasDiff = isFileOperation && part.fileDiff && part.status === 'completed';

  return (
    <div className="border border-line rounded-lg overflow-hidden bg-surface-subtle/30">
      {/* 头部：工具名称、状态、时长 */}
      <button
        onClick={() => hasDetails && setExpanded(!expanded)}
        className={cn(
          'w-full flex items-center gap-2 px-3 py-2 text-sm',
          hasDetails && 'hover:bg-surface-muted/50 cursor-pointer',
          !hasDetails && 'cursor-default'
        )}
      >
        <Wrench size={14} className="text-fg-muted flex-shrink-0" />
        <span className="font-mono text-fg-secondary flex-1 text-left truncate">
          {part.toolName}
        </span>
        {getStatusIcon(part.status)}
        {part.duration && (
          <span className="text-xs text-fg-subtle">{formatDuration(part.duration)}</span>
        )}
        {/* View Diff 按钮 */}
        {hasDiff && onViewDiff && (
          <motion.button
            whileHover={{ scale: 1.05 }}
            whileTap={{ scale: 0.95 }}
            onClick={(e) => {
              e.stopPropagation();
              onViewDiff(part.fileDiff!);
            }}
            className="px-2 py-0.5 text-xs bg-primary-500/10 text-primary-400 rounded hover:bg-primary-500/20 transition-colors"
          >
            <GitCompare size={12} className="inline mr-1" />
            View Diff
          </motion.button>
        )}
        {hasDetails && (
          <span className="text-fg-subtle">
            {expanded ? <ChevronDown size={14} /> : <ChevronRight size={14} />}
          </span>
        )}
      </button>

      {/* 展开的详情 */}
      <AnimatePresence>
        {expanded && hasDetails && (
          <motion.div
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: 'auto', opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            transition={{ duration: 0.2 }}
            className="border-t border-line overflow-hidden"
          >
            <div className="px-3 py-2 space-y-2 text-xs">
              {/* 参数 */}
              {Object.keys(part.arguments).length > 0 && (
                <div>
                  <div className="text-fg-subtle mb-1">Arguments:</div>
                  <pre className="bg-surface-base rounded p-2 overflow-x-auto text-fg-muted max-h-48 overflow-y-auto">
                    {JSON.stringify(part.arguments, null, 2)}
                  </pre>
                </div>
              )}

              {/* 结果 */}
              {part.result !== undefined && (
                <div>
                  <div className="text-fg-subtle mb-1">Result:</div>
                  <pre className="bg-surface-base rounded p-2 overflow-x-auto text-green-400 max-h-48 overflow-y-auto">
                    {typeof part.result === 'string'
                      ? part.result
                      : JSON.stringify(part.result, null, 2)}
                  </pre>
                </div>
              )}

              {/* 错误 */}
              {part.error && (
                <div>
                  <div className="text-red-400 mb-1">Error:</div>
                  <pre className="bg-surface-base rounded p-2 overflow-x-auto text-red-300 max-h-48 overflow-y-auto">
                    {part.error}
                  </pre>
                </div>
              )}
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}

/**
 * 获取工具状态图标
 */
function getStatusIcon(status: ToolStatus) {
  switch (status) {
    case 'pending':
      return <Clock size={14} className="text-yellow-500" />;
    case 'running':
      return <Loader2 size={14} className="text-blue-500 animate-spin" />;
    case 'completed':
      return <CheckCircle2 size={14} className="text-green-500" />;
    case 'error':
      return <AlertCircle size={14} className="text-red-500" />;
  }
}

/**
 * 格式化执行时长
 */
function formatDuration(ms?: number): string {
  if (!ms) return '';
  if (ms < 1000) return `${ms}ms`;
  return `${(ms / 1000).toFixed(1)}s`;
}

