﻿import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { useChatStore, Message } from '../store/chatStore';
import { useGatewayStore } from '../store/gatewayStore';
import { Paperclip, ChevronDown, Terminal, SquarePen, ArrowUp, MessageSquare, Download, Copy, Check } from 'lucide-react';
import { Button, EmptyState } from './ui';
import { listItemVariants, defaultTransition, fadeInVariants } from '../lib/animations';
import { FirstConversationPrompt } from './FirstConversationPrompt';
import { MessageSearch } from './MessageSearch';

export function ChatArea() {
  const {
    messages, currentAgent, isStreaming, currentModel,
    sendMessage: sendToGateway, setCurrentModel, initStreamListener,
    newConversation,
  } = useChatStore();
  const { connectionState, clones, models } = useGatewayStore();

  const [input, setInput] = useState('');
  const [showModelPicker, setShowModelPicker] = useState(false);
  const scrollRef = useRef<HTMLDivElement>(null);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const messageRefs = useRef<Map<string, HTMLDivElement>>(new Map());

  // Get current clone for first conversation prompt
  const currentClone = useMemo(() => {
    if (!currentAgent) return null;
    return clones.find((c) => c.id === currentAgent.id) || null;
  }, [currentAgent, clones]);

  // Check if should show first conversation prompt
  const showFirstPrompt = messages.length === 0 && currentClone && !currentClone.onboardingCompleted;

  // Handle suggestion click from first conversation prompt
  const handleSelectSuggestion = (text: string) => {
    setInput(text);
    textareaRef.current?.focus();
  };

  // Auto-resize textarea
  const adjustTextarea = useCallback(() => {
    const el = textareaRef.current;
    if (el) {
      el.style.height = 'auto';
      el.style.height = Math.min(el.scrollHeight, 160) + 'px';
    }
  }, []);

  // Init agent stream listener on mount
  useEffect(() => {
    const unsub = initStreamListener();
    return unsub;
  }, []);

  // Auto-scroll to bottom on new messages
  useEffect(() => {
    if (scrollRef.current) {
      scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
    }
  }, [messages]);

  const handleSend = () => {
    if (!input.trim() || isStreaming || !connected) return;
    sendToGateway(input);
    setInput('');
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      handleSend();
    }
  };

  const connected = connectionState === 'connected';

  // Navigate to a specific message by ID
  const handleNavigateToMessage = useCallback((messageId: string) => {
    const messageEl = messageRefs.current.get(messageId);
    if (messageEl && scrollRef.current) {
      messageEl.scrollIntoView({ behavior: 'smooth', block: 'center' });
      // Add highlight effect
      messageEl.classList.add('ring-2', 'ring-orange-400', 'ring-offset-2');
      setTimeout(() => {
        messageEl.classList.remove('ring-2', 'ring-orange-400', 'ring-offset-2');
      }, 2000);
    }
  }, []);

  return (
    <div className="flex flex-col h-full">
      {/* Header */}
      <div className="h-14 border-b border-gray-100 dark:border-gray-800 flex items-center justify-between px-6 flex-shrink-0 bg-white dark:bg-gray-900">
        <div className="flex items-center gap-2">
          <h2 className="font-semibold text-gray-900 dark:text-gray-100">{currentAgent?.name || 'ZCLAW'}</h2>
          {isStreaming ? (
            <span className="text-xs text-gray-500 dark:text-gray-400 flex items-center gap-1">
              <span className="w-1.5 h-1.5 bg-gray-500 dark:bg-gray-400 rounded-full thinking-dot"></span>
              正在输入中
            </span>
          ) : (
            <span className={`text-xs flex items-center gap-1 ${connected ? 'text-green-500' : 'text-gray-500 dark:text-gray-400'}`}>
              <span className={`w-1.5 h-1.5 rounded-full ${connected ? 'bg-green-400' : 'bg-gray-300 dark:bg-gray-600'}`}></span>
              {connected ? 'Gateway 已连接' : 'Gateway 未连接'}
            </span>
          )}
        </div>
        <div className="flex items-center gap-2">
          {messages.length > 0 && (
            <MessageSearch onNavigateToMessage={handleNavigateToMessage} />
          )}
          {messages.length > 0 && (
            <Button
              variant="ghost"
              size="sm"
              onClick={newConversation}
              title="新对话"
              aria-label="开始新对话"
              className="flex items-center gap-1.5 text-gray-500 dark:text-gray-400 hover:text-orange-600 dark:hover:text-orange-400 hover:bg-orange-50 dark:hover:bg-orange-900/20"
            >
              <SquarePen className="w-3.5 h-3.5" />
              新对话
            </Button>
          )}
        </div>
      </div>

      {/* Messages */}
      <div ref={scrollRef} className="flex-1 overflow-y-auto custom-scrollbar p-6 space-y-6 bg-white dark:bg-gray-900">
        <AnimatePresence mode="popLayout">
          {messages.length === 0 && (
            <motion.div
              key="empty-state"
              variants={fadeInVariants}
              initial="initial"
              animate="animate"
              exit="exit"
            >
              {showFirstPrompt && currentClone ? (
                <FirstConversationPrompt
                  clone={currentClone}
                  onSelectSuggestion={handleSelectSuggestion}
                />
              ) : (
                <EmptyState
                  icon={<MessageSquare className="w-8 h-8" />}
                  title="欢迎使用 ZCLAW"
                  description={connected ? '发送消息开始对话' : '请先在设置中连接 Gateway'}
                />
              )}
            </motion.div>
          )}

          {messages.map((message) => (
            <motion.div
              key={message.id}
              ref={(el) => { if (el) messageRefs.current.set(message.id, el); }}
              variants={listItemVariants}
              initial="hidden"
              animate="visible"
              layout
              transition={defaultTransition}
            >
              <MessageBubble message={message} />
            </motion.div>
          ))}
        </AnimatePresence>
      </div>

      {/* Input */}
      <div className="border-t border-gray-100 dark:border-gray-800 p-4 bg-white dark:bg-gray-900">
        <div className="max-w-4xl mx-auto">
          <div className="relative flex items-end gap-2 bg-gray-50 dark:bg-gray-800 rounded-2xl border border-gray-200 dark:border-gray-700 p-2 focus-within:border-orange-300 dark:focus-within:border-orange-600 focus-within:ring-2 focus-within:ring-orange-100 dark:focus-within:ring-orange-900/30 transition-all">
            <Button
              variant="ghost"
              size="sm"
              className="p-2 text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
              aria-label="添加附件"
            >
              <Paperclip className="w-5 h-5" />
            </Button>
            <div className="flex-1 py-1">
              <textarea
                ref={textareaRef}
                value={input}
                onChange={(e) => { setInput(e.target.value); adjustTextarea(); }}
                onKeyDown={handleKeyDown}
                placeholder={
                  !connected
                    ? '请先连接 Gateway'
                    : isStreaming
                      ? 'Agent 正在回复...'
                      : `发送给 ${currentAgent?.name || 'ZCLAW'}`
                }
                disabled={isStreaming || !connected}
                rows={1}
                className="w-full bg-transparent border-none focus:outline-none text-gray-700 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-500 disabled:opacity-50 resize-none leading-relaxed mt-1"
                style={{ minHeight: '24px', maxHeight: '160px' }}
              />
            </div>
            <div className="flex items-center gap-2 pr-2 pb-1 relative">
              <Button
                variant="ghost"
                size="sm"
                onClick={() => setShowModelPicker(!showModelPicker)}
                className="flex items-center gap-1 text-xs text-gray-500 dark:text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700"
                aria-label="选择模型"
                aria-expanded={showModelPicker}
              >
                <span>{currentModel}</span>
                <ChevronDown className="w-3 h-3" />
              </Button>
              {showModelPicker && (
                <div className="absolute bottom-full right-8 mb-2 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg py-1 min-w-[160px] max-h-48 overflow-y-auto z-10">
                  {models.length > 0 ? (
                    models.map((model) => (
                      <button
                        key={model.id}
                        onClick={() => { setCurrentModel(model.id); setShowModelPicker(false); }}
                        className={`w-full text-left px-3 py-2 text-xs hover:bg-gray-50 dark:hover:bg-gray-700 ${model.id === currentModel ? 'text-orange-600 dark:text-orange-400 font-medium' : 'text-gray-700 dark:text-gray-300'}`}
                      >
                        {model.name}
                      </button>
                    ))
                  ) : (
                    <div className="px-3 py-2 text-xs text-gray-400">
                      {connected ? '加载中...' : '未连接 Gateway'}
                    </div>
                  )}
                </div>
              )}
              <Button
                variant="primary"
                size="sm"
                onClick={handleSend}
                disabled={isStreaming || !input.trim() || !connected}
                className="w-8 h-8 rounded-full p-0 flex items-center justify-center bg-orange-500 hover:bg-orange-600 text-white"
                aria-label="发送消息"
              >
                <ArrowUp className="w-4 h-4 text-white" />
              </Button>
            </div>
          </div>
          <div className="text-center mt-2 text-xs text-gray-500 dark:text-gray-400">
            Agent 在本地运行，内容由 AI 生成
          </div>
        </div>
      </div>
    </div>
  );
}

/** Code block with copy and download functionality */
function CodeBlock({ code, language, index }: { code: string; language: string; index: number }) {
  const [copied, setCopied] = useState(false);
  const [downloading, setDownloading] = useState(false);

  // Infer filename from language or content
  const inferFilename = (): string => {
    const extMap: Record<string, string> = {
      javascript: 'js', typescript: 'ts', python: 'py', rust: 'rs',
      go: 'go', java: 'java', cpp: 'cpp', c: 'c', csharp: 'cs',
      html: 'html', css: 'css', scss: 'scss', json: 'json',
      yaml: 'yaml', yml: 'yaml', xml: 'xml', sql: 'sql',
      shell: 'sh', bash: 'sh', powershell: 'ps1',
      markdown: 'md', md: 'md', dockerfile: 'dockerfile',
    };

    // Check if language contains a filename (e.g., ```app.tsx)
    if (language.includes('.') || language.includes('/')) {
      return language;
    }

    // Check for common patterns in code
    const codeLower = code.toLowerCase();
    if (codeLower.includes('<!doctype html') || codeLower.includes('<html')) {
      return 'index.html';
    }
    if (codeLower.includes('package.json') || (codeLower.includes('"name"') && codeLower.includes('"version"'))) {
      return 'package.json';
    }
    if (codeLower.startsWith('{') && (codeLower.includes('"import"') || codeLower.includes('"export"'))) {
      return 'config.json';
    }

    // Use language extension
    const ext = extMap[language.toLowerCase()] || language.toLowerCase();
    return `code-${index + 1}.${ext || 'txt'}`;
  };

  const handleCopy = async () => {
    try {
      await navigator.clipboard.writeText(code);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch (err) {
      console.error('Failed to copy:', err);
    }
  };

  const handleDownload = () => {
    setDownloading(true);
    try {
      const filename = inferFilename();
      const blob = new Blob([code], { type: 'text/plain;charset=utf-8' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = filename;
      document.body.appendChild(a);
      a.click();
      document.body.removeChild(a);
      URL.revokeObjectURL(url);
    } catch (err) {
      console.error('Failed to download:', err);
    }
    setTimeout(() => setDownloading(false), 500);
  };

  return (
    <div className="relative group my-2">
      <pre className="bg-gray-900 text-gray-100 rounded-lg p-3 overflow-x-auto text-xs font-mono leading-relaxed">
        {language && (
          <div className="text-gray-500 text-[10px] mb-1 uppercase flex items-center justify-between">
            <span>{language}</span>
          </div>
        )}
        <code>{code}</code>
      </pre>
      {/* Action buttons - show on hover */}
      <div className="absolute top-2 right-2 flex gap-1 opacity-0 group-hover:opacity-100 transition-opacity">
        <button
          onClick={handleCopy}
          className="p-1.5 bg-gray-700 hover:bg-gray-600 rounded text-gray-300 hover:text-white transition-colors"
          title="复制代码"
        >
          {copied ? <Check className="w-3.5 h-3.5 text-green-400" /> : <Copy className="w-3.5 h-3.5" />}
        </button>
        <button
          onClick={handleDownload}
          className="p-1.5 bg-gray-700 hover:bg-gray-600 rounded text-gray-300 hover:text-white transition-colors"
          title="下载文件"
          disabled={downloading}
        >
          <Download className={`w-3.5 h-3.5 ${downloading ? 'animate-pulse' : ''}`} />
        </button>
      </div>
    </div>
  );
}

/** Lightweight markdown renderer — handles code blocks, inline code, bold, italic, links */
function renderMarkdown(text: string): React.ReactNode[] {
  const nodes: React.ReactNode[] = [];
  const lines = text.split('\n');
  let i = 0;

  while (i < lines.length) {
    const line = lines[i];

    // Fenced code block
    if (line.startsWith('```')) {
      const lang = line.slice(3).trim();
      const codeLines: string[] = [];
      i++;
      while (i < lines.length && !lines[i].startsWith('```')) {
        codeLines.push(lines[i]);
        i++;
      }
      i++; // skip closing ```
      nodes.push(
        <CodeBlock key={nodes.length} code={codeLines.join('\n')} language={lang} index={nodes.length} />
      );
      continue;
    }

    // Normal line — parse inline markdown
    nodes.push(
      <span key={nodes.length}>
        {i > 0 && lines[i - 1] !== undefined && !nodes[nodes.length - 1]?.toString().includes('pre') && '\n'}
        {renderInline(line)}
      </span>
    );
    i++;
  }

  return nodes;
}

function renderInline(text: string): React.ReactNode[] {
  const parts: React.ReactNode[] = [];
  // Pattern: **bold**, *italic*, `code`, [text](url)
  const regex = /(\*\*(.+?)\*\*)|(\*(.+?)\*)|(`(.+?)`)|(\[(.+?)\]\((.+?)\))/g;
  let lastIndex = 0;
  let match: RegExpExecArray | null;

  while ((match = regex.exec(text)) !== null) {
    // Text before match
    if (match.index > lastIndex) {
      parts.push(text.slice(lastIndex, match.index));
    }

    if (match[1]) {
      // **bold**
      parts.push(<strong key={parts.length} className="font-semibold">{match[2]}</strong>);
    } else if (match[3]) {
      // *italic*
      parts.push(<em key={parts.length}>{match[4]}</em>);
    } else if (match[5]) {
      // `code`
      parts.push(
        <code key={parts.length} className="bg-gray-100 dark:bg-gray-700 text-orange-700 dark:text-orange-400 px-1 py-0.5 rounded text-[0.85em] font-mono">
          {match[6]}
        </code>
      );
    } else if (match[7]) {
      // [text](url)
      parts.push(
        <a key={parts.length} href={match[9]} target="_blank" rel="noopener noreferrer"
          className="text-orange-600 dark:text-orange-400 underline hover:text-orange-700 dark:hover:text-orange-300">{match[8]}</a>
      );
    }

    lastIndex = match.index + match[0].length;
  }

  if (lastIndex < text.length) {
    parts.push(text.slice(lastIndex));
  }

  return parts.length > 0 ? parts : [text];
}

function MessageBubble({ message }: { message: Message }) {
  if (message.role === 'tool') {
    return (
      <div className="ml-12 bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg p-3 text-xs font-mono">
        <div className="flex items-center gap-2 text-gray-500 dark:text-gray-400 mb-1">
          <Terminal className="w-3.5 h-3.5" />
          <span className="font-semibold">{message.toolName || 'tool'}</span>
        </div>
        {message.toolInput && (
          <pre className="text-gray-600 dark:text-gray-300 bg-white dark:bg-gray-900 rounded p-2 mb-1 overflow-x-auto">{message.toolInput}</pre>
        )}
        {message.content && (
          <pre className="text-green-700 dark:text-green-400 bg-white dark:bg-gray-900 rounded p-2 overflow-x-auto">{message.content}</pre>
        )}
      </div>
    );
  }

  const isUser = message.role === 'user';

  // 思考中状态：streaming 且内容为空时显示思考指示器
  const isThinking = message.streaming && !message.content;

  // Download message as Markdown file
  const handleDownloadMessage = () => {
    if (!message.content) return;
    const timestamp = new Date().toISOString().slice(0, 10);
    const filename = `message-${timestamp}.md`;
    const blob = new Blob([message.content], { type: 'text/markdown;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  return (
    <div className={`flex gap-4 ${isUser ? 'justify-end' : ''}`}>
      <div
        className={`w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0 ${isUser ? 'bg-gray-200 dark:bg-gray-600 text-gray-600 dark:text-gray-200 order-last' : 'agent-avatar text-white'}`}
      >
        {isUser ? '用' : 'Z'}
      </div>
      <div className={isUser ? 'max-w-2xl' : 'flex-1 max-w-3xl'}>
        {isThinking ? (
          // 思考中指示器
          <div className="flex items-center gap-2 px-4 py-3 text-gray-500 dark:text-gray-400">
            <div className="flex gap-1">
              <span className="w-2 h-2 bg-gray-400 dark:bg-gray-500 rounded-full animate-bounce" style={{ animationDelay: '0ms' }} />
              <span className="w-2 h-2 bg-gray-400 dark:bg-gray-500 rounded-full animate-bounce" style={{ animationDelay: '150ms' }} />
              <span className="w-2 h-2 bg-gray-400 dark:bg-gray-500 rounded-full animate-bounce" style={{ animationDelay: '300ms' }} />
            </div>
            <span className="text-sm">思考中...</span>
          </div>
        ) : (
          <div className={`p-4 shadow-sm ${isUser ? 'chat-bubble-user shadow-md' : 'chat-bubble-assistant'} relative group`}>
            <div className={`leading-relaxed whitespace-pre-wrap ${isUser ? 'text-white' : 'text-gray-700 dark:text-gray-200'}`}>
              {message.content
                ? (isUser ? message.content : renderMarkdown(message.content))
                : '...'}
              {message.streaming && <span className="inline-block w-1.5 h-4 bg-orange-500 animate-pulse ml-0.5 align-text-bottom rounded-sm" />}
            </div>
            {message.error && (
              <p className="text-xs text-red-500 mt-2">{message.error}</p>
            )}
            {/* Download button for AI messages - show on hover */}
            {!isUser && message.content && !message.streaming && (
              <button
                onClick={handleDownloadMessage}
                className="absolute top-2 right-2 p-1.5 bg-gray-200/80 dark:bg-gray-700/80 hover:bg-gray-300 dark:hover:bg-gray-600 rounded text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition-colors opacity-0 group-hover:opacity-100"
                title="下载为 Markdown"
              >
                <Download className="w-3.5 h-3.5" />
              </button>
            )}
          </div>
        )}
      </div>
    </div>
  );
}
