﻿import {
  AppstoreOutlined,
  CalendarOutlined,
  CheckOutlined,
  CloudUploadOutlined,
  DeleteOutlined,
  FilterOutlined,
  InfoCircleOutlined,
  PauseCircleOutlined,
  PlusOutlined,
  SyncOutlined,
  UnorderedListOutlined,
  UserOutlined,
} from "@ant-design/icons";
import {
  App,
  Button,
  Card,
  Empty,
  Input,
  List,
  Popconfirm,
  Radio,
  Select,
  Skeleton,
  Space,
  Table,
  Tag,
  Typography,
} from "antd";
import dayjs from "dayjs";
import React, { useEffect, useRef, useState } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";

import { listUsers } from "../../api";
import {
  deleteMeeting,
  getMeetingCreateConfig,
  getMeetingPage,
  getMeetingProgressBatch,
  getRealtimeMeetingSessionStatus,
  getRealtimeMeetingSessionStatuses,
  type MeetingCreateConfig,
  type MeetingProgress,
  type MeetingVO,
  type RealtimeMeetingSessionStatus,
  retryScheduleMeeting,
} from "../../api/business/meeting";
import { MeetingCreateDrawer, type MeetingCreateType } from "../../components/business/MeetingCreateDrawer";
import AppPagination from "../../components/shared/AppPagination";
import DataListPanel from "../../components/shared/DataListPanel";
import SectionCard from "../../components/shared/SectionCard";
import type { SysUser } from "../../types";
import PageContainer from "../../components/shared/PageContainer";
import "./Meetings.css";

const { Title, Text } = Typography;
const { Search } = Input;

const CURRENT_PLATFORM = "WEB" as const;
const PAUSED_DISPLAY_STATUS = 5;
const REALTIME_ACTIVE_DISPLAY_STATUS = 6;
const REALTIME_IDLE_DISPLAY_STATUS = 7;
const ALL_STATUS_FILTER = "all";
const CARD_PAGE_SIZE = 12;
const TABLE_PAGE_SIZE = 10;
const QUEUED_RETRY_THRESHOLD_MS = 2 * 60 * 1000;
const MEETING_STATUS_FILTER_OPTIONS = [
  { label: "全部状态", value: ALL_STATUS_FILTER, color: "#8c8c8c", bgColor: "#f5f5f5" },
  { label: "数据初始化", value: "0", color: "#8c8c8c", bgColor: "#f5f5f5" },
  { label: "转译音频", value: "1", color: "#1890ff", bgColor: "#e6f7ff" },
  { label: "生成总结", value: "2", color: "#faad14", bgColor: "#fff7e6" },
  { label: "处理完成", value: "3", color: "#52c41a", bgColor: "#f6ffed" },
  { label: "处理失败", value: "4", color: "#ff4d4f", bgColor: "#fff1f0" },
] as const;
const DEFAULT_CREATE_CONFIG: MeetingCreateConfig = {
  offlineEnabled: true,
  realtimeEnabled: true,
  offlineAudioMaxSizeMb: 1024,
};

const isRealtimeMeetingCandidate = (item: MeetingVO) =>
  item.meetingType === "REALTIME" || (!item.meetingType && item.status === 0 && !item.audioUrl);

const canControlRealtimeFromCurrentPlatform = (item: MeetingVO) =>
  !item.meetingSource || item.meetingSource === CURRENT_PLATFORM;

const getMeetingSourceLabel = (source?: MeetingVO["meetingSource"]) =>
  source === "ANDROID" ? "安卓端" : "Web端";

const getRealtimeSourceLabel = (item: MeetingVO) => getMeetingSourceLabel(item.meetingSource);

const isPausedRealtimeSessionStatus = (status?: RealtimeMeetingSessionStatus["status"]) =>
  status === "PAUSED_EMPTY" || status === "PAUSED_RESUMABLE";

const canOpenRealtimeSession = (status?: RealtimeMeetingSessionStatus["status"]) =>
  status === "PAUSED_EMPTY"
  || status === "PAUSED_RESUMABLE"
  || status === "ACTIVE"
  || status === "IDLE";

const hasLatestGenerationFailure = (item: MeetingVO) =>
  item.latestChapterAttemptStatus === 3 || item.latestSummaryAttemptStatus === 3;

const shouldTrackGenerationProgress = (item: MeetingVO) =>
  item.status === 0 || item.status === 1 || item.status === 2;

const isTerminalMeetingProgress = (progress?: MeetingProgress | null) =>
  !!progress && (
    progress.percent === 100
    || progress.percent < 0
    || progress.unifiedStatus?.statusCode === "COMPLETED"
    || progress.unifiedStatus?.statusCode?.startsWith("FAILED_")
  );

const isUnifiedTerminalProgress = (progress?: MeetingProgress | null) =>
  !!progress && (
    progress.unifiedStatus?.statusCode === "COMPLETED"
    || progress.unifiedStatus?.statusCode?.startsWith("FAILED_")
  );

const getUnifiedStatusCode = (progress: MeetingProgress | null | undefined) =>
  progress?.unifiedStatus?.statusCode;

const isWaitingUploadProgress = (progress: MeetingProgress | null | undefined) =>
  getUnifiedStatusCode(progress) === "WAITING_UPLOAD";

const getEffectiveStatus = (item: MeetingVO, progress: MeetingProgress | null) => {
  const unifiedStatusCode = getUnifiedStatusCode(progress);
  if (unifiedStatusCode === "WAITING_UPLOAD") {
    return 8;
  }
  if (unifiedStatusCode === "INITIALIZING") {
    return 0;
  }
  if (unifiedStatusCode === "TRANSCRIBING") {
    return 1;
  }
  if (unifiedStatusCode === "SUMMARIZING") {
    return 2;
  }
  if (unifiedStatusCode === "COMPLETED") {
    return 3;
  }
  if (unifiedStatusCode?.startsWith("FAILED_")) {
    return 4;
  }
  const status = item.displayStatus ?? item.status;
  // 如果处于初始化中但已经有进度，则视为转译音频中
  if (status === 0 && progress && progress.percent > 0) {
    return 1;
  }
  if (status === 0 || status === 1 || status === 2) {
    return status;
  }
  if (hasLatestGenerationFailure(item)) {
    return 4;
  }
  return status;
};

const canManageMeeting = (meeting: MeetingVO) => {
  try {
    const profileStr = sessionStorage.getItem("userProfile");
    if (!profileStr) {
      return false;
    }
    const profile = JSON.parse(profileStr);
    return profile.isPlatformAdmin === true || profile.isTenantAdmin === true || profile.userId === meeting.creatorId;
  } catch {
    return false;
  }
};

const canRetryQueuedMeeting = (meeting: MeetingVO, progress: MeetingProgress | null) => {
  if (!canManageMeeting(meeting) || getEffectiveStatus(meeting, progress) !== 0) {
    return false;
  }
  if (!progress?.queuedAt) {
    return false;
  }
  return dayjs().diff(dayjs(progress.queuedAt)) >= QUEUED_RETRY_THRESHOLD_MS;
};

const applyRealtimeSessionStatus = (item: MeetingVO, sessionStatus?: RealtimeMeetingSessionStatus): MeetingVO => {
  if (!sessionStatus) {
    return item;
  }
  if (sessionStatus.status === "PAUSED_EMPTY" || sessionStatus.status === "PAUSED_RESUMABLE") {
    return { ...item, displayStatus: PAUSED_DISPLAY_STATUS, realtimeSessionStatus: sessionStatus.status };
  }
  if (sessionStatus.status === "ACTIVE") {
    return { ...item, displayStatus: REALTIME_ACTIVE_DISPLAY_STATUS, realtimeSessionStatus: sessionStatus.status };
  }
  if (sessionStatus.status === "IDLE" && isRealtimeMeetingCandidate(item)) {
    return { ...item, displayStatus: REALTIME_IDLE_DISPLAY_STATUS, realtimeSessionStatus: sessionStatus.status };
  }
  return { ...item, realtimeSessionStatus: sessionStatus.status };
};

const IntegratedStatusTag: React.FC<{ meeting: MeetingVO; progress: MeetingProgress | null; className?: string; style?: React.CSSProperties }> = ({ meeting, progress, className, style }) => {
  const effectiveStatus = getEffectiveStatus(meeting, progress);
  const statusConfig: Record<number, { text: string; color: string; bgColor: string; icon: React.ReactNode }> = {
    0: { text: "数据初始化", color: "#8c8c8c", bgColor: "rgba(140, 140, 140, 0.1)", icon: <SyncOutlined spin /> },
    1: { text: "转译音频", color: "#1890ff", bgColor: "rgba(24, 144, 255, 0.1)", icon: <SyncOutlined spin /> },
    2: { text: "生成总结", color: "#faad14", bgColor: "rgba(250, 173, 20, 0.1)", icon: <SyncOutlined spin /> },
    3: { text: "处理完成", color: "#52c41a", bgColor: "rgba(82, 196, 26, 0.1)", icon: <CheckOutlined /> },
    4: { text: "处理失败", color: "#ff4d4f", bgColor: "rgba(255, 77, 79, 0.1)", icon: <InfoCircleOutlined /> },
    5: { text: "暂停中", color: "#d48806", bgColor: "rgba(212, 136, 6, 0.1)", icon: <PauseCircleOutlined /> },
    6: { text: "进行中", color: "#3c70f5", bgColor: "#eef4ff", icon: <SyncOutlined spin /> },
    7: { text: "待开始", color: "#595959", bgColor: "rgba(89, 89, 89, 0.1)", icon: <InfoCircleOutlined /> },
    8: { text: "待上传录音文件", color: "#13a8a8", bgColor: "rgba(19, 168, 168, 0.1)", icon: <CloudUploadOutlined /> },
  };
  const config = statusConfig[effectiveStatus] || statusConfig[0];
  const displayConfig = progress?.unifiedStatus?.statusText
    ? { ...config, text: progress.unifiedStatus.statusText }
    : config;
  const isProcessing = shouldTrackGenerationProgress(meeting) && !isUnifiedTerminalProgress(progress);
  const percent = isProcessing ? progress?.percent || 0 : 0;

  const statusStyle = {
    ...style,
    "--meeting-status-color": displayConfig.color,
    "--meeting-status-bg": displayConfig.bgColor,
    "--meeting-status-border": `${displayConfig.color}33`,
  } as React.CSSProperties;

  return (
    <div className={["meeting-status-tag", isProcessing ? "is-processing" : "", className].filter(Boolean).join(" ")} style={statusStyle}>
      {isProcessing && percent > 0 && (
        <div
          className="meeting-status-tag__progress"
          style={{
            width: `${percent}%`,
          }}
        />
      )}
      <span className="meeting-status-tag__icon">
        {isProcessing ? <SyncOutlined spin className="meeting-status-tag__spin-icon" /> : displayConfig.icon}
      </span>
      <span>{displayConfig.text}</span>
      {isProcessing && <span className="meeting-status-tag__percent">{percent}%</span>}
    </div>
  );
};

const TableStatusCell: React.FC<{ meeting: MeetingVO; progress: MeetingProgress | null }> = ({ meeting, progress }) => {
  return <IntegratedStatusTag meeting={meeting} progress={progress} className="meeting-status-tag--table" />;
};

const getMeetingTagList = (tags: unknown) => {
  const normalizeMeetingTag = (tag: unknown) => String(tag).replace(/^#+\s*/, '').trim();

  if (Array.isArray(tags)) {
    return tags.map(normalizeMeetingTag).filter(Boolean);
  }
  if (typeof tags === "string") {
    return tags.split(",").map(normalizeMeetingTag).filter(Boolean);
  }
  return [];
};

const MeetingCardItem: React.FC<{
  item: MeetingVO;
  config: { text: string; color: string; bgColor: string };
  progress: MeetingProgress | null;
  onOpenMeeting: (meeting: MeetingVO) => void;
  onRetrySchedule: (meeting: MeetingVO) => void;
  onDelete: (id: number) => void;
  retrying: boolean;
}> = ({ item, config, progress, onOpenMeeting, onRetrySchedule, onDelete, retrying }) => {
  const effectiveStatus = getEffectiveStatus(item, progress);
  const isProcessing = shouldTrackGenerationProgress(item);
  const isWaitingUpload = isWaitingUploadProgress(progress) || effectiveStatus === 8;
  const isPaused = effectiveStatus === PAUSED_DISPLAY_STATUS;
  const isRealtimeActive = effectiveStatus === REALTIME_ACTIVE_DISPLAY_STATUS;
  const isRealtimeIdle = effectiveStatus === REALTIME_IDLE_DISPLAY_STATUS;
  const isCrossPlatformRealtime = (isPaused || isRealtimeActive || isRealtimeIdle) && !canControlRealtimeFromCurrentPlatform(item);
  const crossPlatformHint = `在 ${getRealtimeSourceLabel(item)} 继续`;
  const canRetry = canRetryQueuedMeeting(item, progress);
  const ownerName = item.creatorName || "未知";
  const tags = getMeetingTagList(item.tags).slice(0, 2);
  const processingMessage = isWaitingUpload
    ? (progress?.message || progress?.unifiedStatus?.message || config.text)
    : (progress?.unifiedStatus?.message || progress?.message || "深度分析中...");

  const sourceColor = item.meetingSource === "ANDROID" ? "#10b981" : "#3b82f6";

  return (
    <List.Item className="meeting-card-list-item">
      <Card
        hoverable
        onClick={() => onOpenMeeting(item)}
        onKeyDown={(event) => {
          if (event.target !== event.currentTarget) {
            return;
          }
          if (event.key === "Enter" || event.key === " ") {
            event.preventDefault();
            onOpenMeeting(item);
          }
        }}
        role="button"
        tabIndex={0}
        className="meeting-card-v2"
      >
        <div className="meeting-card-v2__top">
          <IntegratedStatusTag meeting={item} progress={progress} className="meeting-status-tag--card" />
          <div className="meeting-card-v2__top-actions">
            <div
              className="meeting-card-v2__source"
              style={{ "--meeting-source-color": sourceColor } as React.CSSProperties}
            >
              <span className="meeting-card-v2__source-dot" />
              {getMeetingSourceLabel(item.meetingSource)}
            </div>
            {canManageMeeting(item) && (
              <div
                className="meeting-card-v2__actions"
                onClick={e => e.stopPropagation()}
              >
                <Popconfirm
                  title="确定删除会议吗？"
                  description="删除后将无法找回该会议记录。"
                  onConfirm={() => onDelete(item.id)}
                  okText="删除"
                  cancelText="取消"
                  okButtonProps={{ danger: true }}
                >
                  <Button type="text" size="small" danger icon={<DeleteOutlined />} title="删除会议" aria-label="删除会议" />
                </Popconfirm>
              </div>
            )}
          </div>
        </div>

        <div className="meeting-card-v2__title-row">
          <Title level={4} className="meeting-card-v2__title" ellipsis={{ tooltip: item.title }}>
            {item.title}
          </Title>
        </div>

        <div className="meeting-card-v2__body">
          {(isProcessing || isPaused || isRealtimeActive || isRealtimeIdle) ? (
            <div 
              className="meeting-card-v2__status-note"
              style={{ "--meeting-progress-color": config.color } as React.CSSProperties}
            >
              <div className="meeting-card-v2__status-inner">
                <div className="meeting-card-v2__status-text">
                  {isProcessing ? <SyncOutlined spin /> : <InfoCircleOutlined />}
                  <span>
                    {isProcessing ? processingMessage : (isCrossPlatformRealtime ? crossPlatformHint : config.text)}
                  </span>
                </div>
                {canRetry && (
                  <Button
                    type="link"
                    size="small"
                    loading={retrying}
                    onClick={(event) => {
                      event.stopPropagation();
                      onRetrySchedule(item);
                    }}
                    className="meeting-card-v2__retry"
                  >
                    重新调度
                  </Button>
                )}
              </div>
            </div>
          ) : (
            <div className="meeting-card-v2__meta">
              <div className="meeting-card-v2__meta-item">
                <CalendarOutlined />
                <span>{dayjs(item.meetingTime).format("MM-DD HH:mm")}</span>
              </div>
            </div>
          )}
        </div>

        <div className="meeting-card-v2__footer">
          <div className="meeting-card-v2__tags">
            {tags.length > 0 ? (
              tags.map(tag => (
                <span key={tag} className="meeting-card-v2__tag">
                  {tag}
                </span>
              ))
            ) : (
              <span className="meeting-card-v2__tag-empty">无标签</span>
            )}
          </div>
          <div
            className="meeting-card-v2__owner"
            title={`所属用户：${ownerName}`}
          >
            <UserOutlined />
            <span>{ownerName}</span>
          </div>
        </div>
      </Card>
    </List.Item>
  );
};

const Meetings: React.FC = () => {
  const { message } = App.useApp();
  const navigate = useNavigate();
  const [searchParams, setSearchParams] = useSearchParams();
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState<MeetingVO[]>([]);
  const [progressMap, setProgressMap] = useState<Record<number, MeetingProgress>>({});
  const [total, setTotal] = useState(0);
  const [current, setCurrent] = useState(1);
  const [displayMode, setDisplayMode] = useState<"card" | "list">("card");
  const [size, setSize] = useState(CARD_PAGE_SIZE);
  const [searchTitle, setSearchTitle] = useState("");
  const [searchKeyword, setSearchKeyword] = useState("");
  const [viewType, setViewType] = useState<"all" | "created" | "involved">("all");
  const [statusFilter, setStatusFilter] = useState<string>(ALL_STATUS_FILTER);
  const [createDrawerVisible, setCreateDrawerVisible] = useState(false);
  const [createDrawerType, setCreateDrawerType] = useState<MeetingCreateType>("upload");
  const [configLoaded, setConfigLoaded] = useState(false);
  const [createConfig, setCreateConfig] = useState<MeetingCreateConfig>({
    offlineEnabled: false,
    realtimeEnabled: false,
    offlineAudioMaxSizeMb: 1024,
  });
  const [, setUserList] = useState<SysUser[]>([]);
  const progressTerminalRefreshRef = useRef<Map<number, string>>(new Map());
  const [retryingMeetingIds, setRetryingMeetingIds] = useState<Record<number, boolean>>({});

  const activeFilterCount = (statusFilter !== ALL_STATUS_FILTER ? 1 : 0) + (searchTitle ? 1 : 0);

  const handlePaginationChange = (page: number, pageSize: number) => {
    setCurrent(pageSize !== size ? 1 : page);
    setSize(pageSize);
  };

  const handleDisplayModeChange = (mode: "card" | "list") => {
    setDisplayMode(mode);
    setSize(mode === "card" ? CARD_PAGE_SIZE : TABLE_PAGE_SIZE);
    setCurrent(1);
  };

  const handleSearch = (value?: string) => {
    const nextValue = (value ?? searchKeyword).trim();
    setSearchKeyword(value ?? searchKeyword);
    setSearchTitle(nextValue);
    setCurrent(1);
  };

  const handleResetFilters = () => {
    setSearchKeyword("");
    setSearchTitle("");
    setStatusFilter(ALL_STATUS_FILTER);
    setCurrent(1);
  };

  const loadBatchProgress = async (meetings: MeetingVO[]) => {
    const trackedIds = meetings.filter(shouldTrackGenerationProgress).map((item) => item.id);
    if (trackedIds.length === 0) {
      progressTerminalRefreshRef.current.clear();
      setProgressMap({});
      return {} as Record<number, MeetingProgress>;
    }
    try {
      const progressRes = await getMeetingProgressBatch(trackedIds, { suppressErrorToast: true });
      const nextProgressMap = progressRes.data?.data || {};
      const activeIds = new Set(trackedIds);
      progressTerminalRefreshRef.current.forEach((_, id) => {
        if (!activeIds.has(id)) {
          progressTerminalRefreshRef.current.delete(id);
        }
      });
      setProgressMap(nextProgressMap);
      return nextProgressMap;
    } catch {
      setProgressMap({});
      return {} as Record<number, MeetingProgress>;
    }
  };

  useEffect(() => {
    const action = searchParams.get("action");
    const type = searchParams.get("type") as MeetingCreateType;
    if (action === "create" && (type === "realtime" || type === "upload")) {
      setCreateDrawerType(type);
      setCreateDrawerVisible(true);
      setSearchParams({});
    }
  }, [searchParams, setSearchParams]);

  useEffect(() => {
    void fetchData();
  }, [current, size, searchTitle, viewType, statusFilter]);

  useEffect(() => {
    const maxPage = Math.max(1, Math.ceil(total / size));
    if (current > maxPage) {
      setCurrent(maxPage);
    }
  }, [current, size, total]);

  useEffect(() => {
    const trackedMeetings = data.filter(shouldTrackGenerationProgress);
    if (trackedMeetings.length === 0) {
      progressTerminalRefreshRef.current.clear();
      setProgressMap({});
      return;
    }

    let cancelled = false;
    let timer: ReturnType<typeof setTimeout> | null = null;
    let requesting = false;

    const poll = async () => {
      if (cancelled || requesting) {
        return;
      }
      requesting = true;
      try {
        const nextProgressMap = await loadBatchProgress(trackedMeetings);
        if (cancelled) {
          return;
        }
        let shouldRefresh = false;
        for (const meeting of trackedMeetings) {
          const progress = nextProgressMap[meeting.id];
          if (!isTerminalMeetingProgress(progress)) {
            progressTerminalRefreshRef.current.delete(meeting.id);
            continue;
          }
          const terminalKey = `${progress.updateAt}:${progress.percent}`;
          if (progressTerminalRefreshRef.current.get(meeting.id) !== terminalKey) {
            progressTerminalRefreshRef.current.set(meeting.id, terminalKey);
            shouldRefresh = true;
          }
        }
        if (shouldRefresh) {
          await fetchData(true);
        }
      } finally {
        requesting = false;
        if (!cancelled) {
          timer = setTimeout(() => {
            void poll();
          }, 3000);
        }
      }
    };

    timer = setTimeout(() => {
      void poll();
    }, 3000);
    return () => {
      cancelled = true;
      if (timer) {
        clearTimeout(timer);
      }
    };
  }, [data, current, size, searchTitle, viewType, statusFilter]);

  useEffect(() => {
    const hasRealtimeSessionsToPoll = data.some(
      (item) => item.realtimeSessionStatus === "ACTIVE" || isPausedRealtimeSessionStatus(item.realtimeSessionStatus),
    );
    if (!hasRealtimeSessionsToPoll) {
      return;
    }
    let cancelled = false;
    let timer: ReturnType<typeof setTimeout> | null = null;
    let requesting = false;

    const poll = async () => {
      if (cancelled || requesting) {
        return;
      }
      requesting = true;
      try {
        await fetchData(true);
      } finally {
        requesting = false;
        if (!cancelled) {
          timer = setTimeout(() => {
            void poll();
          }, 5000);
        }
      }
    };

    timer = setTimeout(() => {
      void poll();
    }, 5000);
    return () => {
      cancelled = true;
      if (timer) {
        clearTimeout(timer);
      }
    };
  }, [data, current, size, searchTitle, viewType, statusFilter]);

  useEffect(() => {
    listUsers().then((users) => setUserList(users || [])).catch(() => setUserList([]));
    getMeetingCreateConfig()
      .then((res) => {
        setCreateConfig(res.data.data || DEFAULT_CREATE_CONFIG);
        setConfigLoaded(true);
      })
      .catch(() => {
        setCreateConfig(DEFAULT_CREATE_CONFIG);
        setConfigLoaded(true);
      });
  }, []);

  const fetchData = async (silent = false) => {
    if (!silent) {
      setLoading(true);
    }
    try {
      const res = await getMeetingPage({
        current,
        size,
        title: searchTitle,
        viewType,
        status: statusFilter === ALL_STATUS_FILTER ? undefined : Number(statusFilter),
      });
      const records = res.data?.data?.records || [];
      let statusMap: Record<number, RealtimeMeetingSessionStatus> = {};
      const realtimeCandidates = records.filter(isRealtimeMeetingCandidate);
      if (realtimeCandidates.length > 0) {
        try {
          const sessionRes = await getRealtimeMeetingSessionStatuses(realtimeCandidates.map((item) => item.id));
          statusMap = sessionRes.data?.data || {};
        } catch {}
      }
      const nextData = records.map((item) => applyRealtimeSessionStatus(item, statusMap[item.id]));
      setData(nextData);
      setTotal(res.data?.data?.total || 0);
      await loadBatchProgress(nextData);
    } finally {
      if (!silent) {
        setLoading(false);
      }
    }
  };

  const handleRetrySchedule = async (meeting: MeetingVO) => {
    setRetryingMeetingIds((currentMap) => ({ ...currentMap, [meeting.id]: true }));
    try {
      const response = await retryScheduleMeeting(meeting.id);
      if (response.data?.data) {
        message.success("已触发重新调度");
      } else {
        message.info("当前没有可重新调度的排队任务");
      }
      await fetchData(true);
    } catch {
      message.error("重新调度失败");
    } finally {
      setRetryingMeetingIds((currentMap) => {
        const nextMap = { ...currentMap };
        delete nextMap[meeting.id];
        return nextMap;
      });
    }
  };

  const handleOpenMeeting = async (meeting: MeetingVO) => {
    if (!isRealtimeMeetingCandidate(meeting)) {
      navigate("/meetings/" + meeting.id);
      return;
    }
    if (!canControlRealtimeFromCurrentPlatform(meeting)) {
      message.info(`该实时会议需在${getRealtimeSourceLabel(meeting)}继续，当前仅支持查看详情`);
      navigate("/meetings/" + meeting.id);
      return;
    }
    if (canOpenRealtimeSession(meeting.realtimeSessionStatus)) {
      navigate("/meeting-live-session/" + meeting.id);
      return;
    }
    if (!canManageMeeting(meeting)) {
      navigate("/meetings/" + meeting.id);
      return;
    }
    try {
      const res = await getRealtimeMeetingSessionStatus(meeting.id);
      if (canOpenRealtimeSession(res.data?.data?.status)) {
        navigate("/meeting-live-session/" + meeting.id);
        return;
      }
    } catch {}
    navigate("/meetings/" + meeting.id);
  };

  const tableColumns = [
    {
      title: "会议标题",
      dataIndex: "title",
      key: "title",
      render: (text: string, record: MeetingVO) => <a className="meetings-table__title-link" onClick={() => handleOpenMeeting(record)}>{text}</a>,
    },
    {
      title: "状态",
      key: "status",
      width: 150,
      render: (_: unknown, record: MeetingVO) => <TableStatusCell meeting={record} progress={progressMap[record.id] || null} />,
    },
    {
      title: "会议时间",
      dataIndex: "meetingTime",
      key: "meetingTime",
      width: 160,
      render: (text: string) => dayjs(text).format("YYYY-MM-DD HH:mm"),
    },
    {
      title: "创建人",
      dataIndex: "creatorName",
      key: "creatorName",
      width: 100,
      render: (text: string) => <Text type="secondary">{text || "未知"}</Text>,
    },
    {
      title: "来源",
      dataIndex: "meetingSource",
      key: "meetingSource",
      width: 80,
      render: (value: MeetingVO["meetingSource"]) => <Tag className="meetings-table__source-tag">{getMeetingSourceLabel(value)}</Tag>,
    },
    {
      title: "参会人",
      dataIndex: "participants",
      key: "participants",
      render: (text: string) => <Text type="secondary" ellipsis className="meetings-table__participants">{text || "无参会人员"}</Text>,
    },
    {
      title: "操作",
      key: "action",
      width: 220,
      render: (_: unknown, record: MeetingVO) => (
        <Space size="middle">
          <Button type="link" size="small" onClick={(e) => { e.stopPropagation(); handleOpenMeeting(record); }}>查看详情</Button>
          {canRetryQueuedMeeting(record, progressMap[record.id] || null) && (
            <Button
              type="link"
              size="small"
              loading={!!retryingMeetingIds[record.id]}
              onClick={(e) => {
                e.stopPropagation();
                void handleRetrySchedule(record);
              }}
            >
              重新调度
            </Button>
          )}
          {canManageMeeting(record) && (
            <Popconfirm title="确定删除吗？" onConfirm={() => deleteMeeting(record.id).then(() => fetchData())}>
              <Button type="link" danger size="small" onClick={(e) => e.stopPropagation()}>删除</Button>
            </Popconfirm>
          )}
        </Space>
      ),
    },
  ];

  const statusConfig: Record<number, { text: string; color: string; bgColor: string }> = {
    0: { text: "数据初始化", color: "#8c8c8c", bgColor: "#f5f5f5" },
    1: { text: "转译音频", color: "#1890ff", bgColor: "#e6f7ff" },
    2: { text: "生成总结", color: "#faad14", bgColor: "#fff7e6" },
    3: { text: "处理完成", color: "#52c41a", bgColor: "#f6ffed" },
    4: { text: "处理失败", color: "#ff4d4f", bgColor: "#fff1f0" },
    5: { text: "会议暂停", color: "#d48806", bgColor: "#fff7e6" },
    6: { text: "实时进行中", color: "#1677ff", bgColor: "#e6f4ff" },
    7: { text: "待开始", color: "#595959", bgColor: "#f5f5f5" },
  };

  return (
    <PageContainer
      title={null}
      className="meetings-page"
    >
      <SectionCard
        title="会议中心"
        description="管理会议记录、处理进度与实时会议入口。"
      >
        <DataListPanel
          className={displayMode === "card" ? "meetings-list-panel meetings-list-panel--cards" : "meetings-list-panel"}
          toolbarClassName="meetings-list-toolbar"
          leftActions={
            <div className="meetings-toolbar-stack">
              <div className="meetings-scope-row">
                <Radio.Group
                  value={viewType}
                  onChange={(e) => { setViewType(e.target.value); setCurrent(1); }}
                  buttonStyle="solid"
                  className="meetings-scope-switch"
                >
                  <Radio.Button value="all">全部</Radio.Button>
                  <Radio.Button value="created">我发起</Radio.Button>
                  <Radio.Button value="involved">我参与</Radio.Button>
                </Radio.Group>
              </div>

              <div className="meetings-toolbar-primary">
                <Space wrap size={10} align="center" className="meetings-primary-actions">
                  {configLoaded && (
                    <Button
                      type="primary"
                      icon={<PlusOutlined />}
                      disabled={!createConfig.offlineEnabled && !createConfig.realtimeEnabled}
                      onClick={() => {
                        if (createConfig.offlineEnabled || createConfig.realtimeEnabled) {
                          setCreateDrawerType(createConfig.offlineEnabled ? "upload" : "realtime");
                          setCreateDrawerVisible(true);
                        }
                      }}
                    >
                      新建会议
                    </Button>
                  )}
                </Space>

                <Space wrap size={10} align="center" className="meetings-filter-actions">
                  <Radio.Group
                    value={displayMode}
                    onChange={(e) => handleDisplayModeChange(e.target.value)}
                    buttonStyle="solid"
                    className="meetings-display-switch"
                  >
                    <Radio.Button value="card"><AppstoreOutlined /></Radio.Button>
                    <Radio.Button value="list"><UnorderedListOutlined /></Radio.Button>
                  </Radio.Group>
                  <Select
                    value={statusFilter}
                    onChange={(value) => { setStatusFilter(value); setCurrent(1); }}
                    className="meetings-status-filter"
                    popupMatchSelectWidth={false}
                    suffixIcon={<FilterOutlined className="meetings-status-filter__suffix" />}
                    options={MEETING_STATUS_FILTER_OPTIONS.map((option) => ({
                      value: option.value,
                      label: (
                        <Space size={8}>
                          <span
                            className="meetings-status-filter-dot"
                            style={{
                              background: option.color,
                            }}
                          />
                          <span>{option.label}</span>
                        </Space>
                      ),
                    }))}
                  />
                  <Search
                    placeholder="搜索会议标题"
                    value={searchKeyword}
                    allowClear
                    enterButton={false}
                    onChange={(e) => {
                      const nextValue = e.target.value;
                      setSearchKeyword(nextValue);
                      if (!nextValue) {
                        setSearchTitle("");
                        setCurrent(1);
                      }
                    }}
                    onSearch={handleSearch}
                    className="meetings-search-input"
                  />
                  {activeFilterCount > 0 && (
                    <Button onClick={handleResetFilters}>
                      清空筛选
                    </Button>
                  )}
                </Space>
              </div>
            </div>
          }
          footer={
            <AppPagination
              variant={displayMode === "card" ? "card" : "table"}
              current={current}
              pageSize={size}
              pageSizeOptions={displayMode === "card" ? ["12", "24", "36", "48"] : undefined}
              total={total}
              onChange={handlePaginationChange}
            />
          }
        >
          {displayMode === "card" ? (
            <div className="meetings-card-scroll">
              <Skeleton loading={loading} active paragraph={{ rows: 8 }}>
                <List
                  grid={{ gutter: [12, 12], xs: 1, sm: 2, md: 2, lg: 3, xl: 4, xxl: 4 }}
                  dataSource={data}
                  renderItem={(item) => {
                    const progress = progressMap[item.id] || null;
                    const visualStatus = getEffectiveStatus(item, progress);
                    const config = statusConfig[visualStatus] || statusConfig[0];
                    return (
                      <MeetingCardItem
                        item={item}
                        config={config}
                        progress={progress}
                        onOpenMeeting={handleOpenMeeting}
                        onRetrySchedule={(meeting) => { void handleRetrySchedule(meeting); }}
                        onDelete={(id) => { deleteMeeting(id).then(() => { message.success('删除成功'); fetchData(); }) }}
                        retrying={!!retryingMeetingIds[item.id]}
                      />
                    );
                  }}
                  locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="开启您的第一场会议分析" /> }}
                />
              </Skeleton>
            </div>
          ) : (
            <Table
              className="meetings-list-table"
              columns={tableColumns}
              dataSource={data}
              rowKey="id"
              loading={loading}
              pagination={false}
              scroll={{ x: "max-content", y: "calc(100vh - 430px)" }}
              onRow={(record) => ({ onClick: () => handleOpenMeeting(record) })}
              locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="开启您的第一场会议分析" /> }}
            />
          )}
        </DataListPanel>
      </SectionCard>

      <MeetingCreateDrawer
        open={createDrawerVisible}
        initialType={createDrawerType}
        onCancel={() => setCreateDrawerVisible(false)}
        onSuccess={() => {
          setCreateDrawerVisible(false);
          void fetchData();
        }}
      />
    </PageContainer>
  );
};

export default Meetings;
