import React, { useEffect, useRef, useState } from 'react';
import { AnimatePresence, motion } from 'motion/react';
import {
  CheckCircle,
  ChevronRight,
  Clock3,
  Copy,
  DownloadCloud,
  File as FileIcon,
  Folder,
  FolderPlus,
  Link as LinkIcon,
  Loader2,
  Monitor,
  Plus,
  Send,
  Shield,
  Smartphone,
  Trash2,
  UploadCloud,
  X,
  LogIn,
} from 'lucide-react';
import { useNavigate, useSearchParams } from 'react-router-dom';

import { useAuth } from '@/src/auth/AuthProvider';
import { Button } from '@/src/components/ui/button';
import { appendTransferRelayHint } from '@/src/lib/transfer-ice';
import { buildTransferShareUrl, getTransferRouterMode } from '@/src/lib/transfer-links';
import {
  createTransferFileManifest,
  createTransferFileManifestMessage,
  createTransferCompleteMessage,
  createTransferFileCompleteMessage,
  createTransferFileId,
  createTransferFileMetaMessage,
  type TransferFileDescriptor,
  SIGNAL_POLL_INTERVAL_MS,
} from '@/src/lib/transfer-protocol';
import {
  shouldPublishTransferProgress,
  resolveTransferChunkSize,
} from '@/src/lib/transfer-runtime';
import { createTransferPeer, type TransferPeerAdapter } from '@/src/lib/transfer-peer';
import {
  DEFAULT_TRANSFER_ICE_SERVERS,
  TRANSFER_HAS_RELAY_SUPPORT,
  createTransferSession,
  listMyOfflineTransferSessions,
  pollTransferSignals,
  postTransferSignal,
  uploadOfflineTransferFile,
} from '@/src/lib/transfer';
import type { TransferMode, TransferSessionResponse } from '@/src/lib/types';
import { cn } from '@/src/lib/utils';

import {
  buildQrImageUrl,
  canSendTransferFiles,
  getAvailableTransferModes,
  formatTransferSize,
  getOfflineTransferSessionLabel,
  getOfflineTransferSessionSize,
  getTransferModeSummary,
  resolveInitialTransferTab,
} from './transfer-state';
import TransferReceive from './TransferReceive';

type SendPhase = 'idle' | 'creating' | 'waiting' | 'connecting' | 'uploading' | 'transferring' | 'completed' | 'error';

function parseJsonPayload<T>(payload: string): T | null {
  try {
    return JSON.parse(payload) as T;
  } catch {
    return null;
  }
}

function getPhaseMessage(mode: TransferMode, phase: SendPhase, errorMessage: string) {
  if (mode === 'OFFLINE') {
    switch (phase) {
      case 'creating':
        return '正在创建离线快传会话并生成取件链接...';
      case 'uploading':
        return '文件正在上传到站点存储，上传完成后 7 天内都可以反复接收。';
      case 'completed':
        return '离线文件已上传完成，接收方现在可以多次下载或存入网盘。';
      case 'error':
        return errorMessage || '离线快传初始化失败，请重试。';
      default:
        return '拖拽文件后会生成离线取件码，并把文件上传到站点存储保留 7 天。';
    }
  }

  switch (phase) {
    case 'creating':
      return '正在创建快传会话并准备 P2P 连接...';
    case 'waiting':
      return '分享链接和二维码已经生成，等待接收端打开页面并选择要接收的文件。';
    case 'connecting':
      return '接收端已进入页面，正在交换浏览器连接信息并同步文件清单...';
    case 'transferring':
      return 'P2P 直连已建立，文件正在发送到对方浏览器。';
    case 'completed':
      return '本次文件已发送完成，对方页面现在可以下载。';
    case 'error':
      return errorMessage || '快传会话初始化失败，请重试。';
    default:
      return '拖拽文件后会自动生成会话、二维码和公开接收页链接。';
  }
}

export default function Transfer() {
  const navigate = useNavigate();
  const { ready: authReady, session: authSession } = useAuth();
  const [searchParams] = useSearchParams();
  const sessionId = searchParams.get('session');
  const isAuthenticated = Boolean(authSession?.token);
  const allowSend = canSendTransferFiles(isAuthenticated);
  const availableTransferModes = getAvailableTransferModes(isAuthenticated);
  const [activeTab, setActiveTab] = useState(() => resolveInitialTransferTab(allowSend, sessionId));

  const [selectedFiles, setSelectedFiles] = useState<File[]>([]);
  const [transferMode, setTransferMode] = useState<TransferMode>('ONLINE');
  const [session, setSession] = useState<TransferSessionResponse | null>(null);
  const [sendPhase, setSendPhase] = useState<SendPhase>('idle');
  const [sendProgress, setSendProgress] = useState(0);
  const [sendError, setSendError] = useState('');
  const [copied, setCopied] = useState(false);
  const [offlineHistory, setOfflineHistory] = useState<TransferSessionResponse[]>([]);
  const [offlineHistoryLoading, setOfflineHistoryLoading] = useState(false);
  const [offlineHistoryError, setOfflineHistoryError] = useState('');
  const [selectedOfflineSession, setSelectedOfflineSession] = useState<TransferSessionResponse | null>(null);
  const [historyCopiedSessionId, setHistoryCopiedSessionId] = useState<string | null>(null);

  const fileInputRef = useRef<HTMLInputElement>(null);
  const folderInputRef = useRef<HTMLInputElement>(null);
  const copiedTimerRef = useRef<number | null>(null);
  const historyCopiedTimerRef = useRef<number | null>(null);
  const pollTimerRef = useRef<number | null>(null);
  const peerRef = useRef<TransferPeerAdapter | null>(null);
  const cursorRef = useRef(0);
  const bootstrapIdRef = useRef(0);
  const totalBytesRef = useRef(0);
  const sentBytesRef = useRef(0);
  const lastSendProgressPublishAtRef = useRef(0);
  const lastPublishedSendProgressRef = useRef(0);
  const sendingStartedRef = useRef(false);
  const manifestRef = useRef<TransferFileDescriptor[]>([]);

  useEffect(() => {
    if (!folderInputRef.current) {
      return;
    }

    folderInputRef.current.setAttribute('webkitdirectory', '');
    folderInputRef.current.setAttribute('directory', '');
  }, []);

  useEffect(() => {
    return () => {
      cleanupCurrentTransfer();
      if (copiedTimerRef.current) {
        window.clearTimeout(copiedTimerRef.current);
      }
      if (historyCopiedTimerRef.current) {
        window.clearTimeout(historyCopiedTimerRef.current);
      }
    };
  }, []);

  useEffect(() => {
    if (!allowSend || sessionId) {
      setActiveTab('receive');
    }
  }, [allowSend, sessionId]);

  useEffect(() => {
    if (!availableTransferModes.includes(transferMode)) {
      setTransferMode('ONLINE');
    }
  }, [availableTransferModes, transferMode]);

  useEffect(() => {
    if (selectedFiles.length === 0) {
      return;
    }

    void bootstrapTransfer(selectedFiles);
  }, [transferMode]);

  useEffect(() => {
    if (!isAuthenticated) {
      setOfflineHistory([]);
      setOfflineHistoryError('');
      setSelectedOfflineSession(null);
      return;
    }

    void loadOfflineHistory();
  }, [isAuthenticated]);

  const totalSize = selectedFiles.reduce((sum, file) => sum + file.size, 0);
  const shareLink = session
    ? buildTransferShareUrl(window.location.origin, session.sessionId, getTransferRouterMode())
    : '';
  const qrImageUrl = shareLink ? buildQrImageUrl(shareLink) : '';
  const transferModeSummary = getTransferModeSummary(transferMode);
  const selectedOfflineSessionShareLink = selectedOfflineSession
    ? buildTransferShareUrl(window.location.origin, selectedOfflineSession.sessionId, getTransferRouterMode())
    : '';
  const selectedOfflineSessionQrImageUrl = selectedOfflineSessionShareLink
    ? buildQrImageUrl(selectedOfflineSessionShareLink)
    : '';

  function navigateBackToLogin() {
    const nextPath = `${window.location.pathname}${window.location.search}`;
    navigate(`/login?next=${encodeURIComponent(nextPath)}`);
  }

  function isOfflineSessionReady(sessionToCheck: TransferSessionResponse) {
    return sessionToCheck.files.every((file) => file.uploaded);
  }

  async function loadOfflineHistory(options?: {silent?: boolean}) {
    if (!isAuthenticated) {
      return;
    }

    if (!options?.silent) {
      setOfflineHistoryLoading(true);
    }
    setOfflineHistoryError('');

    try {
      const sessions = await listMyOfflineTransferSessions();
      setOfflineHistory(sessions);
      setSelectedOfflineSession((current) => {
        if (!current) {
          return current;
        }
        return sessions.find((item) => item.sessionId === current.sessionId) ?? null;
      });
    } catch (error) {
      setOfflineHistoryError(error instanceof Error ? error.message : '离线快传记录加载失败');
    } finally {
      if (!options?.silent) {
        setOfflineHistoryLoading(false);
      }
    }
  }

  function cleanupCurrentTransfer() {
    if (pollTimerRef.current) {
      window.clearInterval(pollTimerRef.current);
      pollTimerRef.current = null;
    }

    const peer = peerRef.current;
    peerRef.current = null;
    peer?.destroy();

    cursorRef.current = 0;
    lastSendProgressPublishAtRef.current = 0;
    lastPublishedSendProgressRef.current = 0;
    sendingStartedRef.current = false;
  }

  function publishSendProgress(nextProgress: number, options?: {force?: boolean}) {
    const normalizedProgress = Math.max(0, Math.min(100, nextProgress));
    const now = globalThis.performance?.now?.() ?? Date.now();
    if (!options?.force && !shouldPublishTransferProgress({
      nextProgress: normalizedProgress,
      previousProgress: lastPublishedSendProgressRef.current,
      now,
      lastPublishedAt: lastSendProgressPublishAtRef.current,
    })) {
      return;
    }

    lastSendProgressPublishAtRef.current = now;
    lastPublishedSendProgressRef.current = normalizedProgress;
    setSendProgress(normalizedProgress);
  }

  function resetSenderState() {
    cleanupCurrentTransfer();
    setSession(null);
    setSelectedFiles([]);
    setSendPhase('idle');
    publishSendProgress(0, {force: true});
    setSendError('');
  }

  async function copyToClipboard(text: string) {
    try {
      await navigator.clipboard.writeText(text);
      setCopied(true);
      if (copiedTimerRef.current) {
        window.clearTimeout(copiedTimerRef.current);
      }
      copiedTimerRef.current = window.setTimeout(() => setCopied(false), 1800);
    } catch {
      setCopied(false);
    }
  }

  function ensureReadyState(nextFiles: File[]) {
    setSelectedFiles(nextFiles);

    if (nextFiles.length === 0) {
      resetSenderState();
      return;
    }

    void bootstrapTransfer(nextFiles);
  }

  function appendFiles(files: FileList | File[]) {
    const nextFiles = [...selectedFiles, ...Array.from(files)];
    ensureReadyState(nextFiles);
  }

  function handleFileSelect(event: React.ChangeEvent<HTMLInputElement>) {
    if (event.target.files?.length) {
      appendFiles(event.target.files);
    }
    event.target.value = '';
  }

  function handleDragOver(event: React.DragEvent) {
    event.preventDefault();
  }

  function handleDrop(event: React.DragEvent) {
    event.preventDefault();
    if (event.dataTransfer.files?.length) {
      appendFiles(event.dataTransfer.files);
    }
  }

  function removeFile(indexToRemove: number) {
    ensureReadyState(selectedFiles.filter((_, index) => index !== indexToRemove));
  }

  async function bootstrapTransfer(files: File[]) {
    const bootstrapId = bootstrapIdRef.current + 1;
    bootstrapIdRef.current = bootstrapId;

    cleanupCurrentTransfer();
    setSendError('');
    setSendPhase('creating');
    publishSendProgress(0, {force: true});
    manifestRef.current = createTransferFileManifest(files);
    totalBytesRef.current = 0;
    sentBytesRef.current = 0;

    try {
      const createdSession = await createTransferSession(files, transferMode);
      if (bootstrapIdRef.current !== bootstrapId) {
        return;
      }

      setSession(createdSession);
      if (createdSession.mode === 'OFFLINE') {
        void loadOfflineHistory({silent: true});
        await uploadOfflineFiles(createdSession, files, bootstrapId);
        return;
      }

      setSendPhase('waiting');
      await setupSenderPeer(createdSession, files, bootstrapId);
    } catch (error) {
      if (bootstrapIdRef.current !== bootstrapId) {
        return;
      }
      setSendPhase('error');
      setSendError(error instanceof Error ? error.message : '快传会话创建失败');
    }
  }

  async function uploadOfflineFiles(createdSession: TransferSessionResponse, files: File[], bootstrapId: number) {
    setSendPhase('uploading');
    totalBytesRef.current = files.reduce((sum, file) => sum + file.size, 0);
    sentBytesRef.current = 0;
    publishSendProgress(0, {force: true});

    for (const [index, file] of files.entries()) {
      if (bootstrapIdRef.current !== bootstrapId) {
        return;
      }

      const sessionFile = createdSession.files[index];
      if (!sessionFile?.id) {
        throw new Error('离线快传文件清单不完整，请重新开始本次发送。');
      }

      let lastLoaded = 0;
      await uploadOfflineTransferFile(createdSession.sessionId, sessionFile.id, file, ({ loaded, total }) => {
        const delta = loaded - lastLoaded;
        lastLoaded = loaded;
        sentBytesRef.current += delta;

        if (loaded >= total) {
          sentBytesRef.current = Math.min(totalBytesRef.current, sentBytesRef.current);
        }

        if (totalBytesRef.current > 0) {
          publishSendProgress(Math.min(99, Math.round((sentBytesRef.current / totalBytesRef.current) * 100)));
        }
      });
    }

    publishSendProgress(100, {force: true});
    setSendPhase('completed');
    void loadOfflineHistory({silent: true});
  }

  async function setupSenderPeer(createdSession: TransferSessionResponse, files: File[], bootstrapId: number) {
    const peer = createTransferPeer({
      initiator: true,
      peerOptions: {
        config: {
          iceServers: DEFAULT_TRANSFER_ICE_SERVERS,
        },
      },
      onSignal: (payload) => {
        void postTransferSignal(createdSession.sessionId, 'sender', 'signal', payload);
      },
      onConnect: () => {
        if (bootstrapIdRef.current !== bootstrapId) {
          return;
        }
        setSendPhase((current) => (current === 'transferring' || current === 'completed' ? current : 'connecting'));
        peer.send(createTransferFileManifestMessage(manifestRef.current));
      },
      onData: (payload) => {
        if (typeof payload !== 'string') {
          return;
        }

        const message = parseJsonPayload<{type?: string; fileIds?: string[]}>(payload);
        if (!message || message.type !== 'receive-request' || !Array.isArray(message.fileIds) || sendingStartedRef.current) {
          return;
        }

        const requestedFiles = manifestRef.current.filter((item) => message.fileIds?.includes(item.id));
        if (requestedFiles.length === 0) {
          return;
        }

        sendingStartedRef.current = true;
        totalBytesRef.current = requestedFiles.reduce((sum, file) => sum + file.size, 0);
        sentBytesRef.current = 0;
        publishSendProgress(0, {force: true});
        void sendSelectedFiles(peer, files, requestedFiles, bootstrapId);
      },
      onError: (error) => {
        if (bootstrapIdRef.current !== bootstrapId) {
          return;
        }
        setSendPhase('error');
        setSendError(appendTransferRelayHint(
          error.message || '数据通道建立失败，请重新开始本次快传。',
          TRANSFER_HAS_RELAY_SUPPORT,
        ));
      },
    });
    peerRef.current = peer;
    startSenderPolling(createdSession.sessionId, bootstrapId);
  }

  function startSenderPolling(sessionId: string, bootstrapId: number) {
    let polling = false;

    pollTimerRef.current = window.setInterval(() => {
      if (polling || bootstrapIdRef.current !== bootstrapId) {
        return;
      }

      polling = true;

      void pollTransferSignals(sessionId, 'sender', cursorRef.current)
        .then(async (response) => {
          if (bootstrapIdRef.current !== bootstrapId) {
            return;
          }

          cursorRef.current = response.nextCursor;

          for (const item of response.items) {
            if (item.type === 'peer-joined') {
              setSendPhase((current) => (current === 'waiting' ? 'connecting' : current));
              continue;
            }

            if (item.type === 'signal') {
              peerRef.current?.applyRemoteSignal(item.payload);
            }
          }
        })
        .catch((error) => {
          if (bootstrapIdRef.current !== bootstrapId) {
            return;
          }
          setSendPhase('error');
          setSendError(error instanceof Error ? error.message : '轮询连接状态失败');
        })
        .finally(() => {
          polling = false;
        });
    }, SIGNAL_POLL_INTERVAL_MS);
  }

  async function sendSelectedFiles(
    peer: TransferPeerAdapter,
    files: File[],
    requestedFiles: TransferFileDescriptor[],
    bootstrapId: number,
  ) {
    setSendPhase('transferring');
    const filesById = new Map(files.map((file) => [createTransferFileId(file), file]));
    const chunkSize = resolveTransferChunkSize();

    for (const descriptor of requestedFiles) {
      if (bootstrapIdRef.current !== bootstrapId || !peer.connected) {
        return;
      }

      const file = filesById.get(descriptor.id);
      if (!file) {
        continue;
      }

      peer.send(createTransferFileMetaMessage(descriptor));

      for (let offset = 0; offset < file.size; offset += chunkSize) {
        if (bootstrapIdRef.current !== bootstrapId || !peer.connected) {
          return;
        }

        const chunk = await file.slice(offset, offset + chunkSize).arrayBuffer();
        await peer.write(chunk);
        sentBytesRef.current += chunk.byteLength;

        if (totalBytesRef.current > 0) {
          publishSendProgress(Math.min(
            99,
            Math.round((sentBytesRef.current / totalBytesRef.current) * 100),
          ));
        }
      }

      peer.send(createTransferFileCompleteMessage(descriptor.id));
    }

    peer.send(createTransferCompleteMessage());
    publishSendProgress(100, {force: true});
    setSendPhase('completed');
  }

  async function copyOfflineSessionLink(sessionToCopy: TransferSessionResponse) {
    const sessionShareLink = buildTransferShareUrl(
      window.location.origin,
      sessionToCopy.sessionId,
      getTransferRouterMode(),
    );
    await navigator.clipboard.writeText(sessionShareLink);
    setHistoryCopiedSessionId(sessionToCopy.sessionId);
    if (historyCopiedTimerRef.current) {
      window.clearTimeout(historyCopiedTimerRef.current);
    }
    historyCopiedTimerRef.current = window.setTimeout(() => {
      setHistoryCopiedSessionId((current) => (current === sessionToCopy.sessionId ? null : current));
    }, 1800);
  }

  return (
    <div className="flex-1 py-6 md:py-10">
      <div className="mx-auto w-full max-w-4xl">
        <div className="text-center mb-10">
          <div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-gradient-to-br from-[#336EFF] via-blue-500 to-cyan-400 shadow-lg shadow-[#336EFF]/20 mb-6">
            <Send className="w-8 h-8 text-white" />
          </div>
          <h1 className="text-3xl font-bold text-white mb-3">快传</h1>
          <p className="text-slate-400">在线快传走浏览器 P2P 一次性传输，离线快传会把文件存到站点存储里保留 7 天，可被反复接收。</p>
        </div>

        <div className="glass-panel border border-white/10 rounded-3xl overflow-hidden bg-[#0f172a]/80 backdrop-blur-xl shadow-2xl">
          {allowSend ? (
            <div className="flex border-b border-white/10">
              <button
                onClick={() => setActiveTab('send')}
                className={cn(
                  'flex-1 py-5 text-center font-medium transition-colors relative',
                  activeTab === 'send' ? 'text-white' : 'text-slate-400 hover:text-slate-200 hover:bg-white/5',
                )}
              >
                <div className="flex items-center justify-center gap-2">
                  <UploadCloud className="w-5 h-5" />
                  发送文件
                </div>
                {activeTab === 'send' ? (
                  <motion.div layoutId="activeTransferTab" className="absolute bottom-0 left-0 right-0 h-0.5 bg-[#336EFF]" />
                ) : null}
              </button>
              <button
                onClick={() => setActiveTab('receive')}
                className={cn(
                  'flex-1 py-5 text-center font-medium transition-colors relative',
                  activeTab === 'receive' ? 'text-white' : 'text-slate-400 hover:text-slate-200 hover:bg-white/5',
                )}
              >
                <div className="flex items-center justify-center gap-2">
                  <DownloadCloud className="w-5 h-5" />
                  接收文件
                </div>
                {activeTab === 'receive' ? (
                  <motion.div layoutId="activeTransferTab" className="absolute bottom-0 left-0 right-0 h-0.5 bg-[#336EFF]" />
                ) : null}
              </button>
            </div>
          ) : null}

          <div className="p-8 min-h-[420px] flex flex-col relative min-w-0">
            {authReady && !isAuthenticated ? (
              <div className="mb-6 flex flex-col gap-3 rounded-2xl border border-blue-400/15 bg-blue-500/10 px-4 py-4 text-sm text-blue-100 md:flex-row md:items-center md:justify-between">
                <p className="leading-6">
                  当前无需登录即可在线发送、在线接收和离线接收。只有发离线和把离线文件存入网盘时才需要登录。
                </p>
                <Button
                  type="button"
                  variant="outline"
                  onClick={navigateBackToLogin}
                  className="shrink-0 border border-white/10 bg-white/10 text-white hover:bg-white/15"
                >
                  <LogIn className="mr-2 h-4 w-4" />
                  返回登录
                </Button>
              </div>
            ) : null}

            <AnimatePresence mode="wait">
              {activeTab === 'send' ? (
                <motion.div
                  key="send"
                  initial={{ opacity: 0, x: -20 }}
                  animate={{ opacity: 1, x: 0 }}
                  exit={{ opacity: 0, x: 20 }}
                  transition={{ duration: 0.2 }}
                  className="flex-1 flex flex-col h-full min-w-0"
                >
                  {availableTransferModes.length > 1 ? (
                    <div className="mb-6 grid gap-3 md:grid-cols-2">
                      {availableTransferModes.map((mode) => {
                        const summary = getTransferModeSummary(mode);
                        const active = transferMode === mode;

                        return (
                          <button
                            key={mode}
                            type="button"
                            onClick={() => setTransferMode(mode)}
                            className={cn(
                              'rounded-2xl border p-4 text-left transition-colors',
                              active
                                ? 'border-blue-400/40 bg-blue-500/10'
                                : 'border-white/10 bg-white/[0.03] hover:bg-white/[0.05]',
                            )}
                          >
                            <div className="flex items-center justify-between gap-3">
                              <p className="text-sm font-semibold text-white">{summary.title}</p>
                              <span className={cn(
                                'rounded-full px-2.5 py-1 text-[11px] font-medium',
                                active ? 'bg-blue-400/15 text-blue-100' : 'bg-white/10 text-slate-300',
                              )}>
                                {mode === 'ONLINE' ? '一次接收' : '7 天多次'}
                              </span>
                            </div>
                            <p className="mt-2 text-sm leading-6 text-slate-400">{summary.description}</p>
                          </button>
                        );
                      })}
                    </div>
                  ) : null}

                  {selectedFiles.length === 0 ? (
                    <div
                      className="flex-1 border-2 border-dashed border-white/10 rounded-2xl flex flex-col items-center justify-center p-10 transition-colors hover:border-[#336EFF]/50 hover:bg-[#336EFF]/5"
                      onDragOver={handleDragOver}
                      onDrop={handleDrop}
                    >
                      <div className="w-20 h-20 rounded-full bg-blue-500/10 flex items-center justify-center mb-6">
                        <UploadCloud className="w-10 h-10 text-[#336EFF]" />
                      </div>
                      <h3 className="text-xl font-medium text-white mb-2">拖拽文件或文件夹到此处</h3>
                      <p className="text-slate-400 mb-8 text-center max-w-md">
                        {transferModeSummary.description}
                      </p>
                      <div className="flex flex-col sm:flex-row items-center gap-4">
                        <Button onClick={() => fileInputRef.current?.click()} className="bg-[#336EFF] hover:bg-blue-600 text-white px-8">
                          <FileIcon className="w-4 h-4 mr-2" />
                          选择文件
                        </Button>
                        <Button
                          onClick={() => folderInputRef.current?.click()}
                          variant="outline"
                          className="border-white/10 hover:bg-white/10 text-slate-300 px-8"
                        >
                          <Folder className="w-4 h-4 mr-2" />
                          选择文件夹
                        </Button>
                      </div>
                    </div>
                  ) : (
                    <div className="flex-1 flex flex-col md:flex-row gap-8">
                      <div className="flex-1 flex flex-col items-center justify-center bg-black/20 rounded-2xl p-8 border border-white/5 relative min-w-0">
                        <button onClick={resetSenderState} className="absolute top-4 right-4 text-slate-500 hover:text-white transition-colors" aria-label="取消发送">
                          <X className="w-5 h-5" />
                        </button>

                        <h3 className="text-slate-400 text-sm font-medium mb-2 uppercase tracking-widest">取件码</h3>
                        <div className="text-5xl md:text-6xl font-bold text-white tracking-[0.2em] mb-8 font-mono">
                          {session?.pickupCode ?? '......'}
                        </div>

                        {qrImageUrl ? (
                          <div className="bg-white p-4 rounded-2xl mb-6 shadow-[0_18px_48px_rgba(15,23,42,0.18)]">
                            <img src={qrImageUrl} alt="快传分享二维码" className="w-44 h-44 rounded-xl" />
                          </div>
                        ) : null}

                        <div className="w-full max-w-xs rounded-2xl border border-white/10 bg-black/30 p-3 mb-4">
                          <div className="flex items-center gap-2 text-xs uppercase tracking-[0.24em] text-slate-500 mb-2">
                            <LinkIcon className="w-3.5 h-3.5" />
                            分享链接
                          </div>
                          <div className="text-sm text-slate-200 font-mono truncate">{shareLink || '会话创建中...'}</div>
                        </div>

                        <Button
                          variant="outline"
                          className="w-full max-w-xs border-white/10 hover:bg-white/10 text-slate-200"
                          onClick={() => void copyToClipboard(shareLink)}
                          disabled={!shareLink}
                        >
                          {copied ? <CheckCircle className="w-4 h-4 mr-2 text-emerald-400" /> : <Copy className="w-4 h-4 mr-2" />}
                          {copied ? '已复制' : '复制链接'}
                        </Button>
                      </div>

                      <div className="flex-1 flex flex-col min-w-0">
                        <div className="flex items-center justify-between mb-4 gap-4">
                          <div>
                            <h3 className="text-lg font-medium text-white">待发送文件</h3>
                            <span className="text-sm text-slate-400">{selectedFiles.length} 个项目 • {formatTransferSize(totalSize)}</span>
                          </div>
                          <Button
                            size="sm"
                            variant="outline"
                            className="h-8 border-white/10 hover:bg-white/10 text-slate-300 px-2 shrink-0"
                            onClick={() => folderInputRef.current?.click()}
                          >
                            <FolderPlus className="w-4 h-4 mr-1" />
                            添加文件夹
                          </Button>
                        </div>

                        <div className="flex-1 overflow-y-auto pr-2 space-y-3 max-h-[300px] mb-4">
                          {selectedFiles.map((file, index) => (
                            <div key={`${file.name}-${index}`} className="flex items-center gap-3 bg-white/5 border border-white/5 rounded-xl p-3 group transition-colors hover:bg-white/10">
                              <div className="w-10 h-10 rounded-lg bg-blue-500/10 flex items-center justify-center shrink-0">
                                <FileIcon className="w-5 h-5 text-blue-400" />
                              </div>
                              <div className="flex-1 min-w-0">
                                <p className="text-sm font-medium text-slate-200 truncate">{file.name}</p>
                                <p className="text-xs text-slate-500">{formatTransferSize(file.size)}</p>
                              </div>
                              <button
                                onClick={() => removeFile(index)}
                                className="p-2 text-slate-500 hover:text-red-400 opacity-100 md:opacity-0 group-hover:opacity-100 transition-opacity"
                                title="移除文件"
                              >
                                <Trash2 className="w-4 h-4" />
                              </button>
                            </div>
                          ))}
                        </div>

                        <button
                          onClick={() => fileInputRef.current?.click()}
                          className="w-full flex items-center justify-center gap-2 py-4 border-2 border-dashed border-white/10 rounded-xl text-slate-400 hover:text-white hover:border-white/30 hover:bg-white/5 transition-colors mb-6 shrink-0"
                        >
                          <Plus className="w-5 h-5" />
                          <span className="font-medium">添加更多文件</span>
                        </button>

                        <div className={cn(
                          'mt-auto rounded-xl p-4 flex items-start gap-4 border',
                          sendPhase === 'error'
                            ? 'bg-rose-500/10 border-rose-500/20'
                            : sendPhase === 'completed'
                              ? 'bg-emerald-500/10 border-emerald-500/20'
                              : 'bg-blue-500/10 border-blue-500/20',
                        )}>
                          {sendPhase === 'completed' ? (
                            <CheckCircle className="w-6 h-6 text-emerald-400 shrink-0" />
                          ) : (
                            <Loader2 className={cn(
                              'w-6 h-6 shrink-0',
                              sendPhase === 'error' ? 'text-rose-400' : 'text-blue-400 animate-spin',
                            )} />
                          )}
                          <div className="min-w-0">
                            <p className={cn(
                              'text-sm font-medium',
                              sendPhase === 'error'
                                ? 'text-rose-300'
                                : sendPhase === 'completed'
                                  ? 'text-emerald-300'
                                  : 'text-blue-300',
                            )}>
                              {getPhaseMessage(transferMode, sendPhase, sendError)}
                            </p>
                            <p className="text-xs text-slate-400 mt-1">
                              发送进度 {sendProgress}%{session ? ` · 会话有效期至 ${new Date(session.expiresAt).toLocaleString('zh-CN', {month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit'})}` : ''}
                            </p>
                          </div>
                        </div>
                      </div>
                    </div>
                  )}

                  {isAuthenticated ? (
                    <div className="mt-8 rounded-2xl border border-white/10 bg-white/[0.03] p-5">
                      <div className="mb-4 flex items-center justify-between gap-4">
                        <div>
                          <h3 className="text-base font-semibold text-white">我的离线快传</h3>
                          <p className="mt-1 text-sm text-slate-400">
                            这里只保留未过期的离线快传记录，点击即可重新查看取件码和分享链接。
                          </p>
                        </div>
                        <Button
                          type="button"
                          size="sm"
                          variant="outline"
                          onClick={() => void loadOfflineHistory()}
                          className="h-8 shrink-0 border-white/10 bg-transparent px-3 text-slate-300 hover:bg-white/10"
                        >
                          刷新
                        </Button>
                      </div>

                      {offlineHistoryLoading && offlineHistory.length === 0 ? (
                        <div className="rounded-2xl border border-white/5 bg-black/10 px-4 py-10 text-center text-sm text-slate-400">
                          正在加载离线快传记录...
                        </div>
                      ) : offlineHistoryError ? (
                        <div className="rounded-2xl border border-rose-500/20 bg-rose-500/10 px-4 py-4 text-sm text-rose-200">
                          {offlineHistoryError}
                        </div>
                      ) : offlineHistory.length === 0 ? (
                        <div className="rounded-2xl border border-white/5 bg-black/10 px-4 py-10 text-center text-sm text-slate-400">
                          你还没有发过离线快传。
                        </div>
                      ) : (
                        <div className="grid gap-3">
                          {offlineHistory.map((historySession) => {
                            const ready = isOfflineSessionReady(historySession);

                            return (
                              <button
                                key={historySession.sessionId}
                                type="button"
                                onClick={() => setSelectedOfflineSession(historySession)}
                                className="group flex w-full items-center justify-between gap-4 rounded-2xl border border-white/8 bg-black/10 px-4 py-4 text-left transition-colors hover:border-[#336EFF]/30 hover:bg-white/[0.04]"
                              >
                                <div className="min-w-0 flex-1">
                                  <div className="flex items-center gap-3">
                                    <p className="truncate text-sm font-semibold text-white">
                                      {getOfflineTransferSessionLabel(historySession)}
                                    </p>
                                    <span className={cn(
                                      'rounded-full px-2.5 py-1 text-[11px] font-medium',
                                      ready ? 'bg-emerald-500/15 text-emerald-200' : 'bg-amber-500/15 text-amber-100',
                                    )}>
                                      {ready ? '可接收' : '上传中'}
                                    </span>
                                  </div>
                                  <div className="mt-2 flex flex-wrap items-center gap-x-4 gap-y-1 text-xs text-slate-400">
                                    <span>取件码 {historySession.pickupCode}</span>
                                    <span>{historySession.files.length} 个项目</span>
                                    <span>{getOfflineTransferSessionSize(historySession)}</span>
                                    <span>
                                      到期于 {new Date(historySession.expiresAt).toLocaleString('zh-CN', {
                                        month: '2-digit',
                                        day: '2-digit',
                                        hour: '2-digit',
                                        minute: '2-digit',
                                      })}
                                    </span>
                                  </div>
                                </div>
                                <ChevronRight className="h-5 w-5 shrink-0 text-slate-500 transition-colors group-hover:text-white" />
                              </button>
                            );
                          })}
                        </div>
                      )}
                    </div>
                  ) : null}

                  <input type="file" multiple className="hidden" ref={fileInputRef} onChange={handleFileSelect} />
                  <input type="file" multiple className="hidden" ref={folderInputRef} onChange={handleFileSelect} />
                </motion.div>
              ) : (
                <motion.div
                  key="receive"
                  initial={{ opacity: 0, x: 20 }}
                  animate={{ opacity: 1, x: 0 }}
                  exit={{ opacity: 0, x: -20 }}
                  transition={{ duration: 0.2 }}
                  className="flex-1 flex flex-col h-full min-w-0 w-full"
                >
                  <TransferReceive embedded />
                </motion.div>
              )}
            </AnimatePresence>
          </div>
        </div>

        <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mt-12">
          <div className="flex items-start gap-4 p-4 rounded-2xl bg-white/[0.02] border border-white/5">
            <div className="w-10 h-10 rounded-full bg-blue-500/10 flex items-center justify-center shrink-0">
              <Smartphone className="w-5 h-5 text-blue-400" />
            </div>
            <div>
              <h4 className="text-sm font-medium text-slate-200 mb-1">扫码直达网页</h4>
              <p className="text-xs text-slate-500 leading-relaxed">二维码不承载文件本身，只负责把另一台设备带到公开接收页。</p>
            </div>
          </div>
          <div className="flex items-start gap-4 p-4 rounded-2xl bg-white/[0.02] border border-white/5">
            <div className="w-10 h-10 rounded-full bg-emerald-500/10 flex items-center justify-center shrink-0">
              <Shield className="w-5 h-5 text-emerald-400" />
            </div>
            <div>
              <h4 className="text-sm font-medium text-slate-200 mb-1">浏览器 P2P 传输</h4>
              <p className="text-xs text-slate-500 leading-relaxed">网页之间通过 WebRTC DataChannel 交换文件字节，后端只做信令和会话协调。</p>
            </div>
          </div>
          <div className="flex items-start gap-4 p-4 rounded-2xl bg-white/[0.02] border border-white/5">
            <div className="w-10 h-10 rounded-full bg-cyan-500/10 flex items-center justify-center shrink-0">
              <Monitor className="w-5 h-5 text-cyan-400" />
            </div>
            <div>
              <h4 className="text-sm font-medium text-slate-200 mb-1">在线一次性，离线可重复</h4>
              <p className="text-xs text-slate-500 leading-relaxed">在线模式适合临时快传，离线模式会保留 7 天，接收后文件也不会立刻消失。</p>
            </div>
          </div>
        </div>
      </div>

      <AnimatePresence>
        {selectedOfflineSession ? (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[70] flex items-center justify-center bg-[#020817]/75 px-4 py-6 backdrop-blur-md"
          >
            <motion.div
              initial={{ opacity: 0, scale: 0.96, y: 16 }}
              animate={{ opacity: 1, scale: 1, y: 0 }}
              exit={{ opacity: 0, scale: 0.96, y: 16 }}
              transition={{ duration: 0.18 }}
              className="relative w-full max-w-[34rem] overflow-hidden rounded-[2rem] border border-white/10 bg-[#0d1528]/95 p-8 shadow-[0_30px_120px_rgba(0,0,0,0.45)]"
            >
              <button
                type="button"
                onClick={() => setSelectedOfflineSession(null)}
                className="absolute right-5 top-5 rounded-full p-2 text-slate-500 transition-colors hover:bg-white/5 hover:text-white"
                aria-label="关闭离线快传详情"
              >
                <X className="h-7 w-7" />
              </button>

              <div className="text-center">
                <p className="text-sm tracking-[0.3em] text-slate-400">取件码</p>
                <div className="mt-5 font-mono text-[4.5rem] font-bold leading-none tracking-[0.32em] text-white">
                  {selectedOfflineSession.pickupCode}
                </div>
              </div>

              {selectedOfflineSessionQrImageUrl ? (
                <div className="mx-auto mt-10 w-fit rounded-[2rem] bg-white p-5 shadow-[0_18px_60px_rgba(15,23,42,0.32)]">
                  <img
                    src={selectedOfflineSessionQrImageUrl}
                    alt="离线快传二维码"
                    className="h-64 w-64 rounded-2xl"
                  />
                </div>
              ) : null}

              <div className="mt-8 rounded-[1.7rem] border border-white/10 bg-[#0a1122] px-5 py-4">
                <div className="mb-3 flex items-center gap-2 text-xs uppercase tracking-[0.24em] text-slate-500">
                  <LinkIcon className="h-4 w-4" />
                  分享链接
                </div>
                <div className="truncate text-[1.05rem] text-slate-100">
                  {selectedOfflineSessionShareLink}
                </div>
              </div>

              <Button
                type="button"
                variant="outline"
                className="mt-5 h-16 w-full rounded-[1.35rem] border-white/10 bg-transparent text-xl text-white hover:bg-white/5"
                onClick={() => void copyOfflineSessionLink(selectedOfflineSession)}
              >
                <Copy className="mr-3 h-6 w-6" />
                {historyCopiedSessionId === selectedOfflineSession.sessionId ? '已复制链接' : '复制链接'}
              </Button>

              <div className="mt-6 flex flex-wrap items-center gap-x-4 gap-y-2 text-sm text-slate-400">
                <span>{getOfflineTransferSessionLabel(selectedOfflineSession)}</span>
                <span>{selectedOfflineSession.files.length} 个项目</span>
                <span>{getOfflineTransferSessionSize(selectedOfflineSession)}</span>
                <span className={cn(
                  isOfflineSessionReady(selectedOfflineSession) ? 'text-emerald-300' : 'text-amber-200',
                )}>
                  {isOfflineSessionReady(selectedOfflineSession) ? '文件已就绪，可重复接收' : '文件仍在上传中'}
                </span>
              </div>

              <div className="mt-3 flex items-center gap-2 text-sm text-slate-500">
                <Clock3 className="h-4 w-4" />
                有效期至 {new Date(selectedOfflineSession.expiresAt).toLocaleString('zh-CN', {
                  year: 'numeric',
                  month: '2-digit',
                  day: '2-digit',
                  hour: '2-digit',
                  minute: '2-digit',
                })}
              </div>
            </motion.div>
          </motion.div>
        ) : null}
      </AnimatePresence>
    </div>
  );
}
