﻿import {
  AppstoreOutlined,
  AudioOutlined,
  CalendarOutlined,
  CheckOutlined,
  CloudUploadOutlined,
  DeleteOutlined,
  EditOutlined,
  FilterOutlined,
  InfoCircleOutlined,
  PauseCircleOutlined,
  PlusOutlined,
  SearchOutlined,
  SettingOutlined,
  SyncOutlined,
  TeamOutlined,
  UnorderedListOutlined,
  UserOutlined,
} from "@ant-design/icons";
import {
  App,
  Avatar,
  Button,
  Card,
  Dropdown,
  Empty,
  Form,
  Input,
  List,
  Modal,
  Popconfirm,
  Radio,
  Select,
  Skeleton,
  Space,
  Table,
  Tag,
  Typography,
} from "antd";
import dayjs from "dayjs";
import React, { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
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,
  updateMeetingParticipants,
} from "../../api/business/meeting";
import { MeetingCreateDrawer, type MeetingCreateType } from "../../components/business/MeetingCreateDrawer";
import AppPagination from "../../components/shared/AppPagination";
import { usePermission } from "../../hooks/usePermission";
import type { SysUser } from "../../types";
import PageContainer from "../../components/shared/PageContainer";

const { Title, Text } = Typography;
const { Option } = Select;
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 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 shouldPollMeetingCard = (item: MeetingVO) =>
  shouldTrackGenerationProgress(item)
  || item.realtimeSessionStatus === "ACTIVE"
  || isPausedRealtimeSessionStatus(item.realtimeSessionStatus);

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; style?: React.CSSProperties }> = ({ meeting, progress, 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: "#5f51ff", bgColor: "rgba(95, 81, 255, 0.1)", 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;

  return (
    <div
      style={{
        display: "inline-flex",
        alignItems: "center",
        padding: "4px 12px",
        borderRadius: "8px",
        fontSize: "12px",
        fontWeight: 700,
        color: displayConfig.color,
        background: displayConfig.bgColor,
        border: `1px solid ${displayConfig.color}20`,
        gap: "4px",
        position: "relative",
        overflow: "hidden",
        ...style
      }}
    >
      {isProcessing && percent > 0 && (
        <div
          style={{
            position: "absolute",
            left: 0,
            bottom: 0,
            height: "2px",
            width: `${percent}%`,
            background: displayConfig.color,
            transition: "width 0.4s ease-out",
            boxShadow: `0 0 8px ${displayConfig.color}`
          }}
        />
      )}
      <span style={{ display: "flex", alignItems: "center" }}>
        {isProcessing ? <SyncOutlined spin style={{ fontSize: 11 }} /> : displayConfig.icon}
      </span>
      <span>{displayConfig.text}</span>
      {isProcessing && <span style={{ opacity: 0.8, fontSize: "11px", fontWeight: 500 }}>{percent}%</span>}
    </div>
  );
};

const TableStatusCell: React.FC<{ meeting: MeetingVO; progress: MeetingProgress | null }> = ({ meeting, progress }) => {
  return <IntegratedStatusTag meeting={meeting} progress={progress} style={{ width: 155 }} />;
};

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 processingMessage = isWaitingUpload
    ? (progress?.message || progress?.unifiedStatus?.message || config.text)
    : (progress?.unifiedStatus?.message || progress?.message || "深度分析中...");

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

  return (
    <List.Item style={{ padding: 0 }}>
      <Card
        hoverable
        onClick={() => onOpenMeeting(item)}
        className="meeting-card-v2"
        style={{
          borderRadius: "20px",
          border: "1px solid rgba(0, 0, 0, 0.04)",
          background: "#ffffff",
          overflow: "hidden",
          transition: "all 0.3s cubic-bezier(0.165, 0.84, 0.44, 1)",
          boxShadow: "0 2px 8px rgba(0, 0, 0, 0.02), 0 1px 2px rgba(0, 0, 0, 0.02)",
          height: "100%",
          display: "flex",
          flexDirection: "column",
          minHeight: "200px"
        }}
        styles={{ body: { padding: "20px 24px", flex: 1, display: "flex", flexDirection: "column" } }}
      >
        {/* Top Section: Status & Source */}
        <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 14 }}>
          <IntegratedStatusTag meeting={item} progress={progress} style={{ width: 155 }} />
          <div 
            style={{ 
              display: "flex", 
              alignItems: "center", 
              gap: "4px", 
              padding: "2px 8px", 
              background: `${sourceColor}08`, 
              borderRadius: "6px",
              color: sourceColor,
              fontSize: "11px",
              fontWeight: 700,
              textTransform: "uppercase",
              letterSpacing: "0.01em"
            }}
          >
            <div style={{ width: "5px", height: "5px", borderRadius: "50%", background: sourceColor }} />
            {getMeetingSourceLabel(item.meetingSource)}
          </div>
        </div>

        {/* Middle Section: Title & Actions */}
        <div style={{ position: "relative", marginBottom: 12 }}>
          <Title level={4} style={{ margin: 0, paddingRight: "32px", fontSize: "16px", lineHeight: 1.4, fontWeight: 700, color: "#1a1a1a" }} ellipsis={{ tooltip: item.title }}>
            {item.title}
          </Title>
          
          {canManageMeeting(item) && (
            <div 
              className="card-actions-v2" 
              style={{ position: "absolute", right: -8, top: -4 }}
              onClick={e => e.stopPropagation()}
            >
              <Popconfirm 
                title="确定删除会议吗？" 
                description="删除后将无法找回该会议记录。"
                onConfirm={() => onDelete(item.id)}
                okText="删除"
                cancelText="取消"
                okButtonProps={{ danger: true }}
              >
                <Button type="text" size="small" shape="circle" icon={<DeleteOutlined style={{ color: "#ff4d4f", fontSize: 13 }} />} />
              </Popconfirm>
            </div>
          )}
        </div>

        {/* Content Section: Progress or Metadata */}
        <div style={{ flex: 1, display: "flex", flexDirection: "column", gap: "8px" }}>
          {(isProcessing || isPaused || isRealtimeActive || isRealtimeIdle) ? (
            <div 
              style={{ 
                padding: "8px 10px", 
                borderRadius: "10px", 
                background: "var(--app-bg-surface-strong)", 
                border: "1px solid rgba(0,0,0,0.02)",
                fontSize: "12px"
              }}
            >
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: "10px" }}>
                <div style={{ display: "flex", alignItems: "center", gap: "6px", minWidth: 0, color: config.color, fontWeight: 600 }}>
                  {isProcessing ? <SyncOutlined spin /> : <InfoCircleOutlined />}
                  <span style={{ fontSize: "12px", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
                    {isProcessing ? processingMessage : (isCrossPlatformRealtime ? crossPlatformHint : config.text)}
                  </span>
                </div>
                {canRetry && (
                  <Button
                    type="link"
                    size="small"
                    loading={retrying}
                    onClick={(event) => {
                      event.stopPropagation();
                      onRetrySchedule(item);
                    }}
                    style={{ paddingInline: 0, height: 18, lineHeight: "18px", flexShrink: 0, fontSize: "12px", fontWeight: 600 }}
                  >
                    重新调度
                  </Button>
                )}
              </div>
            </div>
          ) : (
            <div style={{ display: "flex", flexWrap: "wrap", gap: "12px", color: "#8c8c8c", fontSize: "12px" }}>
              <div style={{ display: "flex", alignItems: "center", gap: "4px" }}>
                <CalendarOutlined style={{ fontSize: "13px", opacity: 0.7 }} />
                <span>{dayjs(item.meetingTime).format("MM-DD HH:mm")}</span>
              </div>
            </div>
          )}
        </div>

        {/* Bottom Section: Tags & Navigate */}
        <div style={{ marginTop: "auto", paddingTop: 12, borderTop: "1px solid rgba(0,0,0,0.04)", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
          <div style={{ display: "flex", gap: "4px", flex: 1, overflow: "hidden" }}>
            {item.tags?.split(",").filter(Boolean).slice(0, 2).map(tag => (
              <span 
                key={tag} 
                style={{ 
                  padding: "1px 8px", 
                  borderRadius: "4px", 
                  background: "#f3f4f6", 
                  color: "#6b7280", 
                  fontSize: "11px", 
                  fontWeight: 600,
                  whiteSpace: "nowrap",
                  maxWidth: "90px",
                  overflow: "hidden",
                  textOverflow: "ellipsis"
                }}
              >
                #{tag}
              </span>
            )) || <span style={{ fontSize: "11px", color: "#bfbfbf" }}>无标签</span>}
          </div>
          <div
            style={{
              height: "28px",
              maxWidth: "112px",
              padding: "0 10px",
              borderRadius: "8px",
              background: "rgba(15, 23, 42, 0.04)",
              color: "#6b7280",
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              gap: "5px",
              overflow: "hidden",
              whiteSpace: "nowrap",
              flexShrink: 0,
              fontSize: "11px",
              fontWeight: 600
            }}
            title={`所属用户：${ownerName}`}
          >
            <UserOutlined style={{ fontSize: "12px", opacity: 0.75, flexShrink: 0 }} />
            <span style={{ overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
              {ownerName}
            </span>
          </div>
        </div>
      </Card>
    </List.Item>
  );
};

const Meetings: React.FC = () => {
  const { message } = App.useApp();
  const { t } = useTranslation();
  const navigate = useNavigate();
  const { can } = usePermission();
  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(8);
  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 [userList, 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" ? 8 : 10);
    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 style={{ fontWeight: 500 }} 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 style={{ fontSize: '11px', margin: 0 }}>{getMeetingSourceLabel(value)}</Tag>,
    },
    {
      title: "参会人",
      dataIndex: "participants",
      key: "participants",
      render: (text: string) => <Text type="secondary" ellipsis style={{ maxWidth: 180 }}>{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="会议中心"
      subtitle="管理会议记录与分析"
      style={{ padding: '20px 32px' }}
      headerExtra={
        <Space size={16} wrap>
          <Radio.Group value={displayMode} onChange={(e) => handleDisplayModeChange(e.target.value)} buttonStyle="solid">
            <Radio.Button value="card"><AppstoreOutlined /></Radio.Button>
            <Radio.Button value="list"><UnorderedListOutlined /></Radio.Button>
          </Radio.Group>
          {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>
      }
      toolbar={
        <Space wrap size={12} style={{ width: "100%", justifyContent: "space-between" }}>
          <Radio.Group value={viewType} onChange={(e) => { setViewType(e.target.value); setCurrent(1); }} buttonStyle="solid">
            <Radio.Button value="all">全部</Radio.Button>
            <Radio.Button value="created">我发起</Radio.Button>
            <Radio.Button value="involved">我参与</Radio.Button>
          </Radio.Group>
          <Space wrap size={10} align="center">
            <Tag
              color={activeFilterCount > 0 ? "processing" : "default"}
              style={{ margin: 0, borderRadius: 999, paddingInline: 10, lineHeight: "24px" }}
            >
              <Space size={6}>
                <FilterOutlined />
                <span>{activeFilterCount > 0 ? `已筛选 ${activeFilterCount} 项` : "未筛选"}</span>
              </Space>
            </Tag>
            <Select
              value={statusFilter}
              onChange={(value) => { setStatusFilter(value); setCurrent(1); }}
              style={{ width: 170 }}
              popupMatchSelectWidth={false}
              suffixIcon={<FilterOutlined style={{ color: "#8c8c8c" }} />}
              options={MEETING_STATUS_FILTER_OPTIONS.map((option) => ({
                value: option.value,
                label: (
                  <Space size={8}>
                    <span
                      style={{
                        width: 8,
                        height: 8,
                        borderRadius: "50%",
                        background: option.color,
                        boxShadow: `0 0 0 4px ${option.bgColor}`,
                        flexShrink: 0,
                      }}
                    />
                    <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}
              style={{ width: 240 }}
            />
            {activeFilterCount > 0 && (
              <Button onClick={handleResetFilters}>
                清空筛选
              </Button>
            )}
          </Space>
        </Space>
      }
    >
      <Card
        className="app-page__content-card"
        style={{ flex: 1, minHeight: 0, overflow: "hidden", display: "flex", flexDirection: "column", border: 'none', background: 'transparent' }}
        styles={{ body: { padding: 0, flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" } }}
      >
        <div className="app-page__table-wrap" style={{ flex: 1, minHeight: 0, overflow: "hidden", padding: "4px" }}>
          {displayMode === "card" ? (
            <div style={{ height: "100%", minHeight: 0, overflowY: "auto", overflowX: "hidden" }}>
              <Skeleton loading={loading} active paragraph={{ rows: 8 }}>
                <List
                  grid={{ gutter: [20, 20], 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), style: { cursor: "pointer" } })}
              locale={{ emptyText: <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="开启您的第一场会议分析" /> }}
            />
          )}
        </div>

        <div style={{ padding: "16px 4px 0", flexShrink: 0, display: 'flex', justifyContent: 'center' }}>
          <AppPagination
            variant={displayMode === "card" ? "card" : "table"}
            current={current}
            pageSize={size}
            total={total}
            onChange={handlePaginationChange}
          />
        </div>
      </Card>

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

      <style>{`
        .meeting-card-v2:hover { transform: translateY(-3px); box-shadow: 0 12px 24px rgba(95, 81, 255, 0.08) !important; border-color: rgba(95, 81, 255, 0.15) !important; }
        .status-bar-active { animation: statusBreathing 2s infinite ease-in-out; }
        @keyframes statusBreathing { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }
        .meetings-list-table.ant-table-wrapper,
        .meetings-list-table.ant-table-wrapper .ant-spin-nested-loading,
        .meetings-list-table.ant-table-wrapper .ant-spin-container,
        .meetings-list-table.ant-table-wrapper .ant-table,
        .meetings-list-table.ant-table-wrapper .ant-table-container {
          height: 100%;
          min-height: 0;
        }
        .meetings-list-table.ant-table-wrapper .ant-table-body {
          max-height: calc(100vh - 430px) !important;
        }
        
        /* Premium Button Styles */
        .ant-btn-primary:not(.ant-btn-dangerous) {
          background: linear-gradient(135deg, #5f51ff, #6c8cff) !important;
          border: none !important;
          box-shadow: 0 4px 12px rgba(95, 81, 255, 0.2) !important;
          transition: all 0.3s ease !important;
        }
        .ant-btn-primary:not(.ant-btn-dangerous):hover {
          transform: translateY(-1px);
          box-shadow: 0 6px 16px rgba(95, 81, 255, 0.3) !important;
          filter: brightness(1.05);
        }
        .ant-btn-default {
          border-color: rgba(228, 232, 245, 0.8) !important;
          background: #fff !important;
          color: #6e7695 !important;
        }
        .ant-btn-default:hover {
          border-color: #5f51ff !important;
          color: #5f51ff !important;
        }
      `}</style>
    </PageContainer>
  );
};

export default Meetings;
