import { useEffect, useMemo, useRef, useState } from 'react';
import { useChat } from '../context/ChatProvider';
import { INSUFFICIENT_BALANCE_NOTICE } from '../hooks/useTKMindChat';
import type { CapabilityMap, PortalUser, SessionSummary } from '../types';
import { useNetworkStatus } from '../hooks/useNetworkStatus';
import { getSessionDisplayName } from '../utils/sessions';
import { isH5OrWechatClient } from '../utils/wechat';
import { BalanceRing } from './BalanceRing';
import { HistorySidebar } from './HistorySidebar';
import { TKMindAvatar } from './TKMindAvatar';
import { ChatPanel } from './ChatPanel';
import { ChatLoadingSpinner } from './ChatLoadingSpinner';
import { ConversationPackagePanel } from './ConversationPackagePanel';
import { WechatBindPrompt } from './WechatBindPrompt';
import { WechatAccountButton } from './WechatAccountButton';
import { ChatHeaderMoreMenu } from './ChatHeaderMoreMenu';
import { NotificationCenter } from './NotificationCenter';
import type { MindSpaceSaveCategory } from '../types';

function RecentSessionRail({
  sessions,
  activeSessionId,
  armedSessionId,
  loading,
  loadingMore,
  hasMore,
  chipWidth,
  variant = 'inline',
  onSelect,
  onLoadMore,
}: {
  sessions: SessionSummary[];
  activeSessionId?: string | null;
  armedSessionId?: string | null;
  loading: boolean;
  loadingMore: boolean;
  hasMore: boolean;
  chipWidth?: number | null;
  variant?: 'inline' | 'floating';
  onSelect: (session: SessionSummary) => void;
  onLoadMore: () => void;
}) {
  const compactLabel = (value: string, maxChars = 8) => {
    const trimmed = String(value ?? '').trim();
    if (!trimmed) return '未命名';
    return trimmed.length > maxChars ? `${trimmed.slice(0, maxChars)}...` : trimmed;
  };

  const railRef = useRef<HTMLDivElement | null>(null);
  const recentSessions = useMemo(() => sessions, [sessions]);
  const [canScrollLeft, setCanScrollLeft] = useState(false);
  const [canScrollRight, setCanScrollRight] = useState(false);

  useEffect(() => {
    const node = railRef.current;
    if (!node) return;

    const updateScrollState = () => {
      const maxScrollLeft = Math.max(0, node.scrollWidth - node.clientWidth);
      setCanScrollLeft(node.scrollLeft > 8);
      setCanScrollRight(node.scrollLeft < maxScrollLeft - 8);
    };

    updateScrollState();
    node.addEventListener('scroll', updateScrollState, { passive: true });
    window.addEventListener('resize', updateScrollState);
    return () => {
      node.removeEventListener('scroll', updateScrollState);
      window.removeEventListener('resize', updateScrollState);
    };
  }, [recentSessions.length]);

  useEffect(() => {
    const node = railRef.current;
    if (!node) return;

    const maybeLoadMore = () => {
      if (!hasMore || loadingMore) return;
      const remaining = node.scrollWidth - (node.scrollLeft + node.clientWidth);
      if (remaining <= 96) onLoadMore();
    };

    maybeLoadMore();
    node.addEventListener('scroll', maybeLoadMore, { passive: true });
    return () => node.removeEventListener('scroll', maybeLoadMore);
  }, [hasMore, loadingMore, onLoadMore, recentSessions.length]);

  const scrollByPage = (direction: -1 | 1) => {
    const node = railRef.current;
    if (!node) return;
    const amount = Math.max(180, Math.round(node.clientWidth * 0.82)) * direction;
    node.scrollBy({ left: amount, behavior: 'smooth' });
  };

  if (!loading && recentSessions.length === 0) return null;

  const isFloating = variant === 'floating';

  return (
    <div
      className={`header-session-rail${isFloating ? ' header-session-rail-floating' : ''}`}
      aria-label="最近对话入口"
      style={
        !isFloating && chipWidth && chipWidth > 0
          ? ({ ['--header-session-chip-width' as string]: `${chipWidth}px` })
          : undefined
      }
    >
      <button
        type="button"
        className="header-session-rail-arrow header-session-rail-arrow-left"
        aria-label="查看更早的最近对话"
        disabled={!canScrollLeft}
        onClick={() => scrollByPage(-1)}
      >
        ‹
      </button>
      <div
        className="header-session-rail-track"
        ref={railRef}
      >
        {recentSessions.map((item) => {
          const active = item.id === activeSessionId;
          const armed = item.id === armedSessionId;
          const displayName = getSessionDisplayName(item);
          return (
            <button
              key={item.id}
              type="button"
              className={`header-session-chip${active ? ' is-active' : ''}${armed ? ' is-armed' : ''}`}
              aria-pressed={active || armed}
              title={displayName}
              onClick={() => onSelect(item)}
            >
              <strong>{compactLabel(displayName, 8)}</strong>
              <span>{armed ? '再次点击' : item.message_count > 0 ? `${item.message_count}条` : '继续'}</span>
            </button>
          );
        })}
        {(loading || loadingMore) && (
          <div className="header-session-chip header-session-chip-loading" aria-hidden="true">
            <strong>{loading ? '加载中…' : '继续加载…'}</strong>
            <span>{loading ? '正在准备最近对话' : '滑到这里会自动接上更多'}</span>
          </div>
        )}
      </div>
      <button
        type="button"
        className="header-session-rail-arrow header-session-rail-arrow-right"
        aria-label="查看更多最近对话"
        disabled={!canScrollRight}
        onClick={() => scrollByPage(1)}
      >
        ›
      </button>
    </div>
  );
}

export function ChatView({
  user,
  capabilities,
  grantedSkills,
  onLogout,
  onOpenSpace,
  onOpenPage,
  onOpenAdmin,
  onOpenFeedback,
}: {
  user?: PortalUser | null;
  capabilities?: CapabilityMap;
  grantedSkills?: string[];
  onUserUpdate?: (user: PortalUser) => void;
  onLogout?: () => void;
  onOpenSpace?: (target?: { categoryCode?: MindSpaceSaveCategory; pageId?: string }) => void;
  onOpenPage?: (pageId: string) => void;
  onOpenAdmin?: () => void;
  onOpenFeedback?: () => void;
}) {
  const {
    session,
    sessions,
    sessionsLoading,
    sessionsLoadingMore,
    sessionsHasMore,
    sessionSearchQuery,
    messages,
    messageHistoryLoadingMore,
    messageHistoryHasMore,
    messageHistoryTotal,
    chatState,
    error,
    notice,
    pendingTool,
    submit,
    stop,
    approveTool,
    newSession,
    switchSession,
    deleteSession,
    loadMoreSessions,
    loadOlderMessages,
    setSessionSearchQuery,
    retryConnect,
    dismissNotice,
    onSidebarOpen,
    balanceCents,
    totalCreditCents,
    tokensUsed,
    subscription,
    openRecharge,
    openSubscribe,
    uploadChatImage,
  } = useChat();
  const online = useNetworkStatus();
  const [sidebarOpen, setSidebarOpen] = useState(false);
  const [packagePanelSession, setPackagePanelSession] = useState<SessionSummary | null>(null);
  const [armedSessionId, setArmedSessionId] = useState<string | null>(null);
  const [desktopChipWidth, setDesktopChipWidth] = useState<number | null>(null);
  const spaceButtonRef = useRef<HTMLButtonElement | null>(null);

  useEffect(() => {
    const node = spaceButtonRef.current;
    if (!node) return;

    const updateWidth = () => {
      const nextWidth = Math.round(node.getBoundingClientRect().width);
      if (nextWidth > 0) setDesktopChipWidth(nextWidth);
    };

    updateWidth();
    const resizeObserver = typeof ResizeObserver !== 'undefined' ? new ResizeObserver(updateWidth) : null;
    resizeObserver?.observe(node);
    window.addEventListener('resize', updateWidth);
    return () => {
      resizeObserver?.disconnect();
      window.removeEventListener('resize', updateWidth);
    };
  }, [onOpenSpace]);

  useEffect(() => {
    if (sidebarOpen) {
      onSidebarOpen();
    }
  }, [sidebarOpen, onSidebarOpen]);

  const showHomeWelcome = messages.length === 0;

  const handleSelectSession = (sessionId: string) => {
    void switchSession(sessionId);
    setSidebarOpen(false);
  };

  const handleOpenConversationPackage = (sessionSummary: SessionSummary) => {
    setPackagePanelSession(sessionSummary);
  };

  const handleRecentSessionSelect = (sessionSummary: SessionSummary) => {
    const isSameSession = session?.id === sessionSummary.id;
    const isArmed = armedSessionId === sessionSummary.id;
    if (isSameSession && isArmed) {
      handleOpenConversationPackage(sessionSummary);
      setArmedSessionId(null);
      return;
    }

    setPackagePanelSession(null);
    setArmedSessionId(sessionSummary.id);
    if (!isSameSession) {
      handleSelectSession(sessionSummary.id);
    }
  };

  const handleNewSession = () => {
    void newSession();
    setSidebarOpen(false);
  };

  const isConnectingTitle = !session && chatState !== 'idle';
  const pendingSessionTitle =
    chatState === 'connecting'
      ? '正在创建新对话…'
      : chatState === 'waiting'
        ? '请求已发出…'
        : '连接中…';
  const sessionTitle = session
    ? getSessionDisplayName(session)
    : chatState === 'idle'
      ? '新对话'
      : pendingSessionTitle;

  const moreMenuItems = [
    ...(onOpenAdmin
      ? [{ id: 'admin', label: '管理', onClick: () => onOpenAdmin() }]
      : []),
    ...(onLogout
      ? [{ id: 'logout', label: '登出', onClick: () => onLogout(), danger: true }]
      : []),
  ];

  const useFloatingSessionRail = useMemo(() => isH5OrWechatClient(), []);

  const recentSessionRailProps = {
    sessions,
    activeSessionId: session?.id,
    armedSessionId,
    loading: sessionsLoading,
    loadingMore: sessionsLoadingMore,
    hasMore: sessionsHasMore,
    onSelect: handleRecentSessionSelect,
    onLoadMore: () => void loadMoreSessions(),
  };

  return (
    <div className={`app-shell${useFloatingSessionRail ? ' app-shell-h5' : ''}`}>
      <HistorySidebar
        open={sidebarOpen}
        sessions={sessions}
        activeSessionId={session?.id}
        loading={sessionsLoading}
        loadingMore={sessionsLoadingMore}
        hasMore={sessionsHasMore}
        searchQuery={sessionSearchQuery}
        onClose={() => setSidebarOpen(false)}
        onSelect={handleSelectSession}
        onNew={handleNewSession}
        onDelete={(sessionId) => void deleteSession(sessionId)}
        onLoadMore={() => void loadMoreSessions()}
        onSearchChange={setSessionSearchQuery}
      />

      <div className={`app${showHomeWelcome ? ' app-home' : ''}`}>
        <div className={useFloatingSessionRail ? 'header-shell header-shell-sticky' : undefined}>
          <header className={`header${showHomeWelcome ? ' header-home' : ''}`}>
            <div className="header-left">
              <button
                type="button"
                className="header-menu-btn"
                aria-label="展开历史对话"
                onClick={() => setSidebarOpen(true)}
              >
                ☰
              </button>
              <TKMindAvatar size="sm" className="header-brand-avatar" />
              <div>
                <div className="header-title">{user?.displayName ?? 'TKMind'}</div>
                <div className="header-sub">
                  {isConnectingTitle ? <ChatLoadingSpinner /> : null}
                  <span>{sessionTitle}</span>
                </div>
              </div>
            </div>
            <div className="header-actions header-actions-desktop">
              {!useFloatingSessionRail && (
                <RecentSessionRail
                  {...recentSessionRailProps}
                  chipWidth={desktopChipWidth}
                />
              )}
            {typeof balanceCents === 'number' && (
              <BalanceRing
                balanceCents={balanceCents}
                totalCreditCents={totalCreditCents}
                tokensUsed={tokensUsed}
                subscription={subscription}
                onRecharge={openRecharge}
                onSubscribe={openSubscribe}
              />
            )}
            <NotificationCenter onOpenRecharge={() => openRecharge(false)} />
            <button
              type="button"
              className="header-icon-btn"
              aria-label="新聊天"
              title="新聊天"
              onClick={() => void handleNewSession()}
            >
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
                <path
                  d="M12 5v14M5 12h14"
                  stroke="currentColor"
                  strokeWidth="1.75"
                  strokeLinecap="round"
                />
              </svg>
            </button>
            {onOpenAdmin && (
              <button type="button" className="ghost-btn" onClick={onOpenAdmin}>
                管理
              </button>
            )}
            {onOpenSpace && (
              <button
                ref={spaceButtonRef}
                type="button"
                className="ghost-btn"
                onClick={() => onOpenSpace?.()}
              >
                我的空间
              </button>
            )}
            {user && <WechatAccountButton returnTo={window.location.pathname} />}
            {onLogout && (
              <button type="button" className="ghost-btn logout-btn" onClick={onLogout}>
                登出
              </button>
            )}
          </div>

          <div className="header-actions header-actions-mobile">
            {!useFloatingSessionRail && (
              <RecentSessionRail
                {...recentSessionRailProps}
                chipWidth={null}
              />
            )}
            {typeof balanceCents === 'number' && (
              <BalanceRing
                balanceCents={balanceCents}
                totalCreditCents={totalCreditCents}
                tokensUsed={tokensUsed}
                subscription={subscription}
                onRecharge={openRecharge}
                onSubscribe={openSubscribe}
              />
            )}
            <NotificationCenter onOpenRecharge={() => openRecharge(false)} />
            <button
              type="button"
              className="header-icon-btn"
              aria-label="新聊天"
              title="新聊天"
              onClick={() => void handleNewSession()}
            >
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
                <path
                  d="M12 5v14M5 12h14"
                  stroke="currentColor"
                  strokeWidth="1.75"
                  strokeLinecap="round"
                />
              </svg>
            </button>
            {onOpenSpace && (
              <button
                type="button"
                className="header-icon-btn"
                aria-label="我的空间"
                title="我的空间"
                onClick={() => onOpenSpace?.()}
              >
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true">
                  <path
                    d="M4 8.5V19a1 1 0 001 1h14a1 1 0 001-1V8.5M4 8.5l8-4.5 8 4.5M4 8.5h16M9 21v-6h6v6"
                    stroke="currentColor"
                    strokeWidth="1.75"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  />
                </svg>
              </button>
            )}
            <ChatHeaderMoreMenu
              items={moreMenuItems}
              returnTo={window.location.pathname}
              showWechat={Boolean(user)}
            />
          </div>
        </header>
        {useFloatingSessionRail && (
          <RecentSessionRail
            {...recentSessionRailProps}
            variant="floating"
            chipWidth={null}
          />
        )}
        </div>

        {!online && (
          <div className="banner banner-offline">网络已断开，请检查连接后重试</div>
        )}

        {user && <WechatBindPrompt returnTo={window.location.pathname} />}

        {typeof balanceCents === 'number' && balanceCents <= 0 && (
          <div className="banner banner-error">
            <span>余额不足，请充值后继续使用</span>
            <button type="button" className="banner-action" onClick={() => openRecharge(false)}>
              去充值
            </button>
          </div>
        )}
        {typeof balanceCents === 'number' && balanceCents > 0 && balanceCents <= 100 && (
          <div className="banner banner-warning">
            <span>余额较低（¥{(balanceCents / 100).toFixed(2)}），建议提前充值</span>
            <button type="button" className="banner-action" onClick={() => openRecharge(false)}>
              去充值
            </button>
          </div>
        )}

        {notice && (
          <div className={`banner${notice === INSUFFICIENT_BALANCE_NOTICE ? ' banner-warning' : ' banner-info'}`}>
            <span style={{ whiteSpace: 'pre-line' }}>{notice}</span>
            {notice === INSUFFICIENT_BALANCE_NOTICE ? (
              <>
                <button type="button" className="banner-action" onClick={() => openRecharge(false)}>
                  去充值
                </button>
                <button type="button" className="banner-dismiss" onClick={dismissNotice}>
                  知道了
                </button>
              </>
            ) : (
              <button type="button" className="banner-dismiss" onClick={dismissNotice}>
                知道了
              </button>
            )}
          </div>
        )}

        {error && (
          <div className="banner banner-error">
            <span>{error}</span>
            <button type="button" className="banner-action" onClick={() => void retryConnect()}>
              重试
            </button>
          </div>
        )}

        <ChatPanel
          variant="full"
          user={user}
          messages={messages}
          historyLoadingMore={messageHistoryLoadingMore}
          historyHasMore={messageHistoryHasMore}
          historyTotal={messageHistoryTotal}
          chatState={chatState}
          pendingTool={pendingTool}
          session={session}
          capabilities={capabilities}
          grantedSkills={grantedSkills}
          onSubmit={(text, imageUrls, previewImageUrls, options) =>
            void submit(
              text,
              { messageId: options?.messageId, forceDeepReasoning: options?.forceDeepReasoning },
              imageUrls,
              previewImageUrls,
            )
          }
          onUploadImage={(file, onProgress, options) =>
            uploadChatImage(file, onProgress, { messageId: options?.messageId })
          }
          onLoadOlderMessages={loadOlderMessages}
          onStop={stop}
          onApproveTool={approveTool}
          onPageSaved={(result) => {
            if (result.kind === 'page' && result.pageId) {
              onOpenPage?.(result.pageId);
              return;
            }
            onOpenSpace?.({ categoryCode: result.categoryCode });
          }}
        />
        <ConversationPackagePanel
          sessionId={packagePanelSession?.id ?? null}
          sessionName={packagePanelSession ? getSessionDisplayName(packagePanelSession) : null}
          open={Boolean(packagePanelSession)}
          onClose={() => {
            setPackagePanelSession(null);
            setArmedSessionId(null);
          }}
        />
      </div>
    </div>
  );
}
