import React, { useCallback, useEffect, useRef, useState } from 'react';
import type { ChatSheetProps, QuickAction } from '../../types';
import { WelcomePage } from '../WelcomePage';
import { MessageList } from '../MessageList';
import { InputBar } from '../InputBar';
import { QuickActionBar } from '../QuickActionBar';
import { useChatMessages } from '../../hooks/useChatMessages';
import { useChatSession } from '../../hooks/useChatSession';
import { useTouch } from '../../hooks/useTouch';
import { useVirtualKeyboard } from '../../hooks/useVirtualKeyboard';
import {
  sendChatRequest,
  consumeStream,
  createUserMessage,
  createAssistantMessage,
} from '../../services/chatService';
import styles from './index.module.less';

type SheetMode = 'expanded' | 'collapsed';

export const ChatSheet: React.FC<ChatSheetProps> = ({
  visible,
  onClose,
  apiConfig,
  title,
  hideNavbar = false,
  assistantName = '小亦',
  quickActions,
  initialMessages = [],
  messageActions,
  onEventResult,
  onEventChange,
  eventContent,
  sendOnOpen,
  onSendOnOpenConsumed,
  avatarUrl,
  onQuickActionClick,
  initialVoiceMode,
  collapsed: collapsedProp,
  onMessageDone,
  onParaSourceClick,
  className,
}) => {
  const overlayRef = useRef<HTMLDivElement>(null);
  const sheetRef = useRef<HTMLDivElement>(null);
  const bodyRef = useRef<HTMLDivElement>(null);
  const { messages, addMessage, updateMessage, appendSuggestedQuestions } =
    useChatMessages(initialMessages);
  const { ensureSession } = useChatSession();
  const { keyboardHeight } = useVirtualKeyboard();
  const [sending, setSending] = useState(false);
  const abortRef = useRef<AbortController | null>(null);
  const currentAiMsgIdRef = useRef<string | null>(null);
  const lastAutoSentRef = useRef<string | null>(null);

  const [sheetMode, setSheetMode] = useState<SheetMode>('expanded');
  const [activeQuickActionId, setActiveQuickActionId] = useState<string | undefined>();
  const [activeSceneCode, setActiveSceneCode] = useState<string | undefined>();
  const [showQuickActionBar, setShowQuickActionBar] = useState(false);

  const { touch, start, move } = useTouch();
  const [dragOffset, setDragOffset] = useState(0);
  const draggingRef = useRef(false);
  const dragOffsetRef = useRef(0);
  const mouseStartYRef = useRef(0);

  const DRAG_CLOSE_THRESHOLD = 120;

  useEffect(() => {
    if (visible) {
      setSheetMode('expanded');
    }
  }, [visible]);

  useEffect(() => {
    if (collapsedProp && visible) {
      setSheetMode('collapsed');
    }
  }, [collapsedProp, visible]);

  useEffect(() => {
    const el = sheetRef.current;
    if (!el) return;
    const preventOverscroll = (e: TouchEvent) => {
      if (draggingRef.current && e.cancelable) {
        e.preventDefault();
      }
    };
    el.addEventListener('touchmove', preventOverscroll, { passive: false });
    return () => el.removeEventListener('touchmove', preventOverscroll);
  }, []);

  useEffect(() => {
    const onWindowMouseUp = (e: MouseEvent) => {
      if (!draggingRef.current) return;
      const offset = dragOffsetRef.current;
      draggingRef.current = false;
      dragOffsetRef.current = 0;
      setDragOffset(0);
      if (offset >= DRAG_CLOSE_THRESHOLD) {
        setSheetMode(prev => {
          if (prev === 'expanded') return 'collapsed';
          onClose();
          return prev;
        });
      } else if (offset <= -DRAG_CLOSE_THRESHOLD && sheetMode === 'collapsed') {
        setSheetMode('expanded');
      }
    };
    window.addEventListener('mouseup', onWindowMouseUp);
    return () => window.removeEventListener('mouseup', onWindowMouseUp);
  }, [onClose, sheetMode]);

  const onTouchStart = useCallback(
    (e: React.TouchEvent) => {
      const handle = (e.target as HTMLElement).closest('[data-drag-handle]');
      if (!handle) return;
      start(e);
      draggingRef.current = true;
    },
    [start],
  );

  const onTouchMove = useCallback(
    (e: React.TouchEvent) => {
      if (!draggingRef.current) return;
      if (e.cancelable) e.preventDefault();
      move(e);
      const dy = touch.deltaY;
      if (dy > 0) {
        dragOffsetRef.current = dy;
        setDragOffset(dy);
      } else if (sheetMode === 'collapsed' && dy < 0) {
        dragOffsetRef.current = dy;
        setDragOffset(dy);
      }
    },
    [move, touch, sheetMode],
  );

  const onTouchEnd = useCallback(() => {
    if (!draggingRef.current) return;
    draggingRef.current = false;
    const offset = dragOffsetRef.current;
    dragOffsetRef.current = 0;
    setDragOffset(0);
    if (offset >= DRAG_CLOSE_THRESHOLD) {
      setSheetMode(prev => {
        if (prev === 'expanded') return 'collapsed';
        onClose();
        return prev;
      });
    } else if (offset <= -DRAG_CLOSE_THRESHOLD && sheetMode === 'collapsed') {
      setSheetMode('expanded');
    }
  }, [onClose, sheetMode]);

  const onMouseDown = useCallback((e: React.MouseEvent) => {
    const handle = (e.target as HTMLElement).closest('[data-drag-handle]');
    if (!handle) return;
    e.preventDefault();
    draggingRef.current = true;
    mouseStartYRef.current = e.clientY;
    dragOffsetRef.current = 0;
    setDragOffset(0);
  }, []);

  const onMouseMove = useCallback((e: React.MouseEvent) => {
    if (!draggingRef.current) return;
    e.preventDefault();
    const dy = e.clientY - mouseStartYRef.current;
    if (dy > 0) {
      dragOffsetRef.current = dy;
      setDragOffset(dy);
    } else if (sheetMode === 'collapsed' && dy < 0) {
      dragOffsetRef.current = dy;
      setDragOffset(dy);
    }
  }, [sheetMode]);

  const onMouseUp = useCallback((e: React.MouseEvent) => {
    if (!draggingRef.current) return;
    draggingRef.current = false;
    const offset = dragOffsetRef.current;
    dragOffsetRef.current = 0;
    setDragOffset(0);
    if (offset >= DRAG_CLOSE_THRESHOLD) {
      setSheetMode(prev => {
        if (prev === 'expanded') return 'collapsed';
        onClose();
        return prev;
      });
    } else if (offset <= -DRAG_CLOSE_THRESHOLD && sheetMode === 'collapsed') {
      setSheetMode('expanded');
    }
  }, [onClose, sheetMode]);

  const onMouseLeave = useCallback((e: React.MouseEvent) => {
    if (!draggingRef.current || e.buttons !== 0) return;
    const offset = dragOffsetRef.current;
    draggingRef.current = false;
    dragOffsetRef.current = 0;
    setDragOffset(0);
    if (offset >= DRAG_CLOSE_THRESHOLD) {
      setSheetMode(prev => {
        if (prev === 'expanded') return 'collapsed';
        onClose();
        return prev;
      });
    } else if (offset <= -DRAG_CLOSE_THRESHOLD && sheetMode === 'collapsed') {
      setSheetMode('expanded');
    }
  }, [onClose, sheetMode]);

  const handleExpandFromHistory = useCallback(() => {
    setSheetMode('expanded');
  }, []);

  const showQuickActionPrompts = useCallback(
    (action: QuickAction) => {
      const responseText =
        action.responseText ?? `您好，我可以帮你查询本活动相关的${action.title}。`;
      const questions = action.questions ?? [
        '关于活动的问题',
        '关于活动的问题',
        '关于活动的问题',
      ];

      const aiMsg = createAssistantMessage(responseText);
      aiMsg.status = 'success';
      aiMsg.hideActions = true;
      aiMsg.suggestedQuestions = questions.map((q, i) => ({
        id: `qa-${action.id}-${Date.now()}-${i}`,
        text: q,
      }));
      addMessage(aiMsg);
    },
    [addMessage],
  );

  const handleCardClick = useCallback(
    (action: QuickAction) => {
      setActiveQuickActionId(action.id);
      if (action.sceneCode) setActiveSceneCode(action.sceneCode);
      setShowQuickActionBar(true);
      onQuickActionClick?.(action);
      showQuickActionPrompts(action);
    },
    [onQuickActionClick, showQuickActionPrompts],
  );

  const handleQuickActionPillClick = useCallback(
    (action: QuickAction) => {
      setActiveQuickActionId(action.id);
      if (action.sceneCode) setActiveSceneCode(action.sceneCode);
      showQuickActionPrompts(action);
    },
    [showQuickActionPrompts],
  );

  const handleStop = useCallback(() => {
    abortRef.current?.abort();
    abortRef.current = null;
    if (currentAiMsgIdRef.current) {
      updateMessage(currentAiMsgIdRef.current, prev => ({
        content: prev.content || '',
        status: 'stopped' as const,
      }));
      currentAiMsgIdRef.current = null;
    }
    setSending(false);
  }, [updateMessage]);

  const handleSend = useCallback(
    async (text: string) => {
      if (!apiConfig || sending) return;

      setShowQuickActionBar(true);

      abortRef.current?.abort();
      abortRef.current = new AbortController();

      const userMsg = createUserMessage(text);
      addMessage(userMsg);

      const aiMsg = createAssistantMessage();
      addMessage(aiMsg);
      currentAiMsgIdRef.current = aiMsg.id;

      setSending(true);

      const mergedConfig = activeSceneCode
        ? {
            ...apiConfig,
            headers: {
              ...(apiConfig.headers ?? {}),
              sceneCode: activeSceneCode,
            },
          }
        : apiConfig;

      try {
        const sid = await ensureSession();
        const response = await sendChatRequest(
          mergedConfig,
          text,
          sid || undefined,
          abortRef.current.signal,
        );

        await consumeStream(response, {
          onChunk: fullText => {
            updateMessage(aiMsg.id, { content: fullText, status: 'loading' });
          },
          onDone: fullText => {
            currentAiMsgIdRef.current = null;
            updateMessage(aiMsg.id, { content: fullText, status: 'success' });
            setSending(false);
            onMessageDone?.(aiMsg.id);
          },
          onError: err => {
            if (err.name !== 'AbortError') {
              currentAiMsgIdRef.current = null;
              updateMessage(aiMsg.id, {
                content: '抱歉，请求失败，请重试。',
                status: 'error',
              });
              setSending(false);
              onMessageDone?.(aiMsg.id);
            }
          },
          onSuggestedQuestions: questions => {
            appendSuggestedQuestions(aiMsg.id, questions);
          },
          onAction: actions => {
            onEventChange?.(actions, aiMsg.id);
          },
          onPara: para => {
            updateMessage(aiMsg.id, { para });
          },
        });
      } catch (err: unknown) {
        const e = err as Error;
        if (e.name !== 'AbortError') {
          currentAiMsgIdRef.current = null;
          updateMessage(aiMsg.id, { content: '网络异常，请重试。', status: 'error' });
          setSending(false);
          onMessageDone?.(aiMsg.id);
        }
      }

      if (onEventResult) {
        onEventResult(null, aiMsg.id);
      }
    },
    [
      apiConfig,
      activeSceneCode,
      sending,
      addMessage,
      updateMessage,
      appendSuggestedQuestions,
      ensureSession,
      onEventResult,
      onEventChange,
      onMessageDone,
    ],
  );

  const handleSuggestionClick = useCallback(
    (text: string) => {
      void handleSend(text);
    },
    [handleSend],
  );

  useEffect(() => {
    if (!visible) {
      lastAutoSentRef.current = null;
      return;
    }
    const t = sendOnOpen?.trim();
    if (!t) return;
    if (lastAutoSentRef.current === t) return;
    lastAutoSentRef.current = t;
    onSendOnOpenConsumed?.();
    void handleSend(t);
  }, [visible, sendOnOpen, handleSend, onSendOnOpenConsumed]);

  // 滚动到底部
  useEffect(() => {
    const el = bodyRef.current;
    if (!el) return;

    requestAnimationFrame(() => {
      el.scrollTop = el.scrollHeight;
    });
  }, [messages.length, messages[messages.length - 1]?.content]);

  const isCollapsed = sheetMode === 'collapsed';

  return (
    <div
      ref={overlayRef}
      className={[
        styles.overlay,
        visible ? styles.overlayVisible : '',
        isCollapsed ? styles.overlayCollapsed : '',
        className ?? '',
      ].join(' ')}
    >
      <div
        ref={sheetRef}
        className={[
          styles.sheet,
          isCollapsed ? styles.sheetCollapsed : '',
        ].join(' ')}
        style={{
          transform: visible
            ? `translateY(${dragOffset > 0 ? dragOffset : 0}px)`
            : 'translateY(100%)',
          ...(isCollapsed && dragOffset < 0
            ? { maxHeight: `${665 + Math.abs(dragOffset)}px` }
            : {}),
          transition: draggingRef.current ? 'none' : 'transform 0.3s ease, max-height 0.3s ease',
        }}
        onTouchStart={onTouchStart}
        onTouchMove={onTouchMove}
        onTouchEnd={onTouchEnd}
        onMouseDown={onMouseDown}
        onMouseMove={onMouseMove}
        onMouseUp={onMouseUp}
        onMouseLeave={onMouseLeave}
      >
        {/* 拖拽把手 + 历史问答胶囊 */}
        <div className={`${styles.handle} ${isCollapsed ? styles.handleCollapsed : ''}`} data-drag-handle>
          <div className={styles.handleBar} />
          {isCollapsed && (
            <div className={styles.historyHandle}>
              <div className={styles.historyDivider} />
              <button
                type="button"
                className={styles.historyPill}
                onClick={handleExpandFromHistory}
              >
                历史问答
              </button>
            </div>
          )}
          {isCollapsed && (
            <button
              type="button"
              className={styles.closeBtnCollapsed}
              onClick={(e) => { e.stopPropagation(); onClose(); }}
              onTouchStart={(e) => e.stopPropagation()}
              aria-label="关闭"
            >
              <CloseIcon />
            </button>
          )}
        </div>

        {/* 导航栏：仅展开态显示，可由 hideNavbar 关闭 */}
        {!isCollapsed && !hideNavbar && (
          <div className={styles.navbar}>
            <button type="button" className={styles.backBtn} onClick={onClose} aria-label="返回">
              <BackIcon />
            </button>
            {title && <span className={styles.navTitle}>{title}</span>}
            <div className={styles.navRight} />
          </div>
        )}

        {/* 隐藏导航栏时的右上角关闭按钮 */}
        {!isCollapsed && hideNavbar && (
          <button type="button" className={styles.closeBtn} onClick={onClose} aria-label="关闭">
            <CloseIcon />
          </button>
        )}

        {/* 内容区 */}
        <div ref={bodyRef} className={styles.body}>
          {!isCollapsed && (
            <WelcomePage
              assistantName={assistantName}
              quickActions={quickActions}
              avatarUrl={avatarUrl}
              onCardClick={handleCardClick}
            />
          )}
          {messages.length > 0 && (
            <MessageList
              messages={messages}
              actions={messageActions}
              onSuggestionClick={handleSuggestionClick}
              onParaSourceClick={onParaSourceClick}
              eventContent={eventContent}
            />
          )}
        </div>

        {/* 快捷按钮行：卡片被点击过或用户发送了问题后才显示 */}
        {showQuickActionBar && quickActions && quickActions.length > 0 && (
          <QuickActionBar
            actions={quickActions}
            activeId={activeQuickActionId}
            onActionClick={handleQuickActionPillClick}
          />
        )}

        <InputBar onSend={handleSend} disabled={sending} sending={sending} onStop={handleStop} keyboardOffset={keyboardHeight} initialVoiceMode={initialVoiceMode} />
      </div>
    </div>
  );
};

const BackIcon = () => (
  <svg width="48" height="48" viewBox="0 0 48 48" fill="none">
    <path
      d="M30 36L18 24l12-12"
      stroke="rgba(0,0,0,0.9)"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  </svg>
);

const CloseIcon = () => (
  <svg width="32" height="32" viewBox="0 0 32 32" fill="none">
    <path
      d="M9.15 9.15l13.7 13.7M22.85 9.15l-13.7 13.7"
      stroke="rgba(0,0,0,0.9)"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
    />
  </svg>
);
