import LeftOutlined from "@ant-design/icons/LeftOutlined";
import ReloadOutlined from "@ant-design/icons/ReloadOutlined";
import RightOutlined from "@ant-design/icons/RightOutlined";
import SearchOutlined from "@ant-design/icons/SearchOutlined";
import VideoCameraOutlined from "@ant-design/icons/VideoCameraOutlined";
import { Button, Card, Empty, Form, Input, message, Radio, Select, Tree } from "antd";
import { useEffect, useRef, useState } from "react";
import Page from "zy-react-library/components/Page";
import Video from "zy-react-library/components/Video";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
import { buildPlayableVideoSource } from "~/utils/video";

const IS_ONLINE_ENUM = [
  { name: "离线", bianma: "0" },
  { name: "在线", bianma: "1" },
];
// 巡屏页：
// 1. 左侧树控制参与巡屏的视频范围
// 2. 右侧按宫格展示视频，并支持自动轮巡
// 3. 每个视频卡片都支持截图并进入隐患上报弹窗
const LAYOUT_MODES = [
  { label: "4 宫格", value: 4 },
  { label: "6 宫格", value: 6 },
  { label: "9 宫格", value: 9 },
  { label: "单画面", value: 1 },
];
const PLAY_READY_TIMEOUT = 25000;
const PLAY_RETRY_INTERVAL = 5000;

function BatchPlay() {
  const [form] = Form.useForm();
  // 宫格模式、勾选状态、轮巡间隔、当前分组共同决定右侧展示内容。
  const [layoutMode, setLayoutMode] = useState(6);
  const [checkedKeys, setCheckedKeys] = useState([]);
  const [currentGroup, setCurrentGroup] = useState(0);
  // 列表、播放地址、截图弹窗等状态都在页面内独立管理。
  const [loadFailed, setLoadFailed] = useState(false);
  const [videoList, setVideoList] = useState([]);
  const [filteredVideoList, setFilteredVideoList] = useState([]);
  const [playUrls, setPlayUrls] = useState({});
  const [playStatusMap, setPlayStatusMap] = useState({});
  const videoCardRefs = useRef({});
  const playRetryTimersRef = useRef({});
  const playFailTimersRef = useRef({});
  const playTaskIdsRef = useRef({});
  const playRequestingRef = useRef({});

  const query = useGetUrlQuery();

  // 巡屏页批量取播放地址时直接走 fetch，避免全局 loading 干扰页面体验。
  const requestPlayUrlSilently = async (indexCode) => {
    const apiHost = window.__JJB_ENVIRONMENT__?.API_HOST || "";
    const token = window.sessionStorage?.token;
    const tenantCode = window.__JJB_ENVIRONMENT__?.tenantCode;
    const queryString = new URLSearchParams({ indexCode }).toString();
    const response = await fetch(`${apiHost}/videopatrol/fixedCamera/getPlayUrl?${queryString}`, {
      method: "GET",
      headers: {
        ...(token ? { token } : {}),
        ...(tenantCode ? { tenantCode } : {}),
      },
    });

    if (!response.ok) {
      throw new Error(`HTTP_${response.status}`);
    }

    const result = await response.json();
    if (!result?.success) {
      return null;
    }

    return buildPlayableVideoSource(result.data?.url || result.data || null).source || null;
  };

  const clearVideoPlayTimers = (videoId) => {
    if (playRetryTimersRef.current[videoId]) {
      window.clearInterval(playRetryTimersRef.current[videoId]);
      delete playRetryTimersRef.current[videoId];
    }
    if (playFailTimersRef.current[videoId]) {
      window.clearTimeout(playFailTimersRef.current[videoId]);
      delete playFailTimersRef.current[videoId];
    }
  };

  const clearAllVideoPlayTimers = () => {
    Object.keys(playRetryTimersRef.current).forEach(clearVideoPlayTimers);
    Object.keys(playFailTimersRef.current).forEach(clearVideoPlayTimers);
  };

  const isVideoReady = (videoId) => {
    const videoEl = videoCardRefs.current[videoId]?.querySelector("video");
    return !!videoEl && videoEl.readyState >= 2;
  };

  const startVideoRetryMonitor = (video) => {
    const videoId = video?.id?.toString();
    if (!videoId || !video.cameraNumber) {
      return;
    }

    clearVideoPlayTimers(videoId);
    playTaskIdsRef.current[videoId] = (playTaskIdsRef.current[videoId] || 0) + 1;
    const currentTaskId = playTaskIdsRef.current[videoId];
    playRequestingRef.current[videoId] = false;

    const requestLatestPlayUrl = async () => {
      if (playRequestingRef.current[videoId]) {
        return false;
      }
      playRequestingRef.current[videoId] = true;
      try {
        const playUrl = await requestPlayUrlSilently(video.cameraNumber);
        if (playTaskIdsRef.current[videoId] !== currentTaskId) {
          return false;
        }
        if (playUrl) {
          setPlayUrls(prev => ({ ...prev, [videoId]: playUrl }));
          return true;
        }
        return false;
      }
      catch {
        return false;
      }
      finally {
        if (playTaskIdsRef.current[videoId] === currentTaskId) {
          playRequestingRef.current[videoId] = false;
        }
      }
    };

    const attemptPlayback = async () => {
      if (playTaskIdsRef.current[videoId] !== currentTaskId) {
        return;
      }

      if (isVideoReady(videoId)) {
        clearVideoPlayTimers(videoId);
        setPlayStatusMap(prev => ({ ...prev, [videoId]: "success" }));
        return;
      }

      setPlayStatusMap(prev => ({ ...prev, [videoId]: "loading" }));
      await requestLatestPlayUrl();

      if (playTaskIdsRef.current[videoId] !== currentTaskId) {
        return;
      }

      if (isVideoReady(videoId)) {
        clearVideoPlayTimers(videoId);
        setPlayStatusMap(prev => ({ ...prev, [videoId]: "success" }));
      }
    };

    // 巡屏页和固定摄像头查看保持同样节奏：当前宫格中的卡片每 5 秒重新取一次地址，25 秒才判失败。
    playRetryTimersRef.current[videoId] = window.setInterval(() => {
      attemptPlayback();
    }, PLAY_RETRY_INTERVAL);

    playFailTimersRef.current[videoId] = window.setTimeout(() => {
      if (playTaskIdsRef.current[videoId] !== currentTaskId || isVideoReady(videoId)) {
        clearVideoPlayTimers(videoId);
        setPlayStatusMap(prev => ({ ...prev, [videoId]: "success" }));
        return;
      }

      clearVideoPlayTimers(videoId);
      setPlayUrls((prev) => {
        const next = { ...prev };
        delete next[videoId];
        return next;
      });
      setPlayStatusMap(prev => ({ ...prev, [videoId]: "error" }));
    }, PLAY_READY_TIMEOUT);
  };

  // 前端筛选只控制当前巡屏页展示，不会影响数据库数据。
  const filterVideos = (list, values = {}) => {
    const { videoName, isOnline } = values;
    return list.filter((video) => {
      const matchName = !videoName || video.videoName?.includes(videoName);
      const matchStatus = isOnline === undefined || isOnline === "" || video.isOnline?.toString() === isOnline;
      return matchName && matchStatus;
    });
  };

  // 加载视频台账列表，并默认让当前筛选结果全部参与巡屏。
  // 巡屏页左侧树与视频台账列表保持同一取数口径，避免绕开台账权限过滤。
  const loadVideoList = async () => {
    const list = query.videoResourceData ? JSON.parse(query.videoResourceData) : [];
    const filteredList = filterVideos(list, form.getFieldsValue());
    const nextCheckedKeys = filteredList.map(item => item.id?.toString()).filter(Boolean);
    setVideoList(list);
    setFilteredVideoList(filteredList);
    setLoadFailed(false);
    setCheckedKeys(nextCheckedKeys);
    setCurrentGroup(0);
  };

  // 页面首次进入时拉一次视频列表。
  useEffect(() => {
    loadVideoList();
  }, []);

  // 页面卸载时清理自动轮巡定时器。
  useEffect(() => {
    return () => {
      clearAllVideoPlayTimers();
    };
  }, []);

  // 左侧勾选决定参与巡屏的视频集合，右侧只展示当前分组的视频。
  const selectedVideos = videoList.filter(item => checkedKeys.includes(item.id?.toString()));
  const maxGroup = Math.max(Math.ceil(selectedVideos.length / layoutMode) - 1, 0);
  const displayVideos = selectedVideos.slice(
    currentGroup * layoutMode,
    currentGroup * layoutMode + layoutMode,
  );

  // 宫格切换或筛选变化后，如果当前页码越界，自动回到第一页。
  useEffect(() => {
    if (currentGroup > maxGroup) {
      setCurrentGroup(0);
    }
  }, [currentGroup, maxGroup]);

  // 勾选集变化后，静默批量向海康拉取播放地址；
  // 巡屏页不再回退数据库中的原始视频地址。
  useEffect(() => {
    let canceled = false;

    const fetchPlayUrls = async () => {
      if (checkedKeys.length === 0) {
        clearAllVideoPlayTimers();
        setPlayUrls({});
        setPlayStatusMap({});
        return;
      }

      const nextPlayUrls = {};
      const nextPlayStatusMap = {};
      const videosNeedFetch = [];
      for (const video of selectedVideos) {
        const videoId = video.id?.toString();
        if (video.cameraNumber) {
          nextPlayStatusMap[videoId] = "loading";
          videosNeedFetch.push(video);
        }
        else {
          nextPlayStatusMap[videoId] = "error";
        }
      }

      if (!canceled) {
        setPlayUrls(nextPlayUrls);
        setPlayStatusMap(nextPlayStatusMap);
      }

      if (videosNeedFetch.length > 0) {
        const hideLoading = message.loading(`正在获取 ${videosNeedFetch.length} 个视频的播放地址...`, 0);
        let failedCount = 0;
        for (const video of videosNeedFetch) {
          const videoId = video.id?.toString();
          try {
            const playUrl = await requestPlayUrlSilently(video.cameraNumber);
            if (playUrl) {
              nextPlayUrls[videoId] = playUrl;
              // 仅拿到播放地址不代表已经真正出画面；
              // 截图按钮仍需等视频元素 ready 后，再由重试监控把状态切到 success。
              nextPlayStatusMap[videoId] = "loading";
            }
            else {
              failedCount += 1;
              nextPlayStatusMap[videoId] = "error";
            }
          }
          catch {
            failedCount += 1;
            nextPlayStatusMap[videoId] = "error";
          }
        }
        hideLoading();
        if (!canceled) {
          setPlayUrls({ ...nextPlayUrls });
          setPlayStatusMap({ ...nextPlayStatusMap });
          if (failedCount > 0) {
            message.warning(`有 ${failedCount} 个视频播放地址获取失败`);
          }
        }
      }
    };

    fetchPlayUrls();

    return () => {
      canceled = true;
    };
  }, [checkedKeys, videoList]);

  const displayVideoKey = displayVideos.map(video => `${video?.id ?? "empty"}:${video?.cameraNumber ?? ""}`).join("|");

  useEffect(() => {
    const displayVideoIds = new Set(displayVideos.map(video => video?.id?.toString()).filter(Boolean));

    Object.keys(playRetryTimersRef.current).forEach((videoId) => {
      if (!displayVideoIds.has(videoId)) {
        clearVideoPlayTimers(videoId);
      }
    });

    displayVideos.forEach((video) => {
      if (video?.cameraNumber) {
        startVideoRetryMonitor(video);
      }
    });

    return () => {
      displayVideos.forEach((video) => {
        const videoId = video?.id?.toString();
        if (videoId) {
          clearVideoPlayTimers(videoId);
        }
      });
    };
  }, [displayVideoKey]);

  // 手动切换上一组/下一组。
  const handlePrevGroup = () => {
    if (selectedVideos.length === 0)
      return;
    setCurrentGroup(prev => (prev <= 0 ? maxGroup : prev - 1));
  };

  const handleNextGroup = () => {
    if (selectedVideos.length === 0)
      return;
    setCurrentGroup(prev => (prev >= maxGroup ? 0 : prev + 1));
  };

  // 单个卡片播放失败时支持手动重试获取播放地址。
  const retryPlayUrl = async (video) => {
    const videoId = video.id?.toString();
    if (!videoId)
      return;

    if (!video.cameraNumber) {
      setPlayStatusMap(prev => ({ ...prev, [videoId]: "error" }));
      message.warning("当前视频缺少摄像头编号，无法获取播放地址");
      return;
    }

    setPlayStatusMap(prev => ({ ...prev, [videoId]: "loading" }));
    try {
      const playUrl = await requestPlayUrlSilently(video.cameraNumber);
      if (!playUrl) {
        throw new Error("empty play url");
      }
      setPlayUrls(prev => ({ ...prev, [videoId]: playUrl }));
      setPlayStatusMap(prev => ({ ...prev, [videoId]: "loading" }));
      startVideoRetryMonitor(video);
    }
    catch {
      setPlayUrls((prev) => {
        const next = { ...prev };
        delete next[videoId];
        return next;
      });
      setPlayStatusMap(prev => ({ ...prev, [videoId]: "loading" }));
      startVideoRetryMonitor(video);
    }
  };

  // 搜索后只保留命中的视频，并默认全部勾选参与巡屏。
  const handleSearch = (values) => {
    const filtered = filterVideos(videoList, values);
    setFilteredVideoList(filtered);
    setCheckedKeys(filtered.map(item => item.id?.toString()).filter(Boolean));
    setCurrentGroup(0);
  };

  // 重置后恢复完整列表、全选状态，并按当前宫格重新计算是否自动轮巡。
  const handleReset = () => {
    form.resetFields();
    setFilteredVideoList(videoList);
    setCheckedKeys(videoList.map(item => item.id?.toString()).filter(Boolean));
    setCurrentGroup(0);
  };

  // 左侧树节点的在线状态样式与右侧是否参与巡屏同时展示在标题里。
  const renderOnlineStatus = (status) => {
    const statusValue = `${status ?? ""}`;
    const isOnline = statusValue === "1";
    const text = isOnline ? "在线" : "离线";
    return (
      <span
        style={{
          display: "inline-flex",
          alignItems: "center",
          gap: 4,
          padding: "0 6px",
          borderRadius: 10,
          fontSize: 12,
          lineHeight: "20px",
          color: isOnline ? "#389e0d" : "#595959",
          background: isOnline ? "#f6ffed" : "#fafafa",
          border: `1px solid ${isOnline ? "#b7eb8f" : "#d9d9d9"}`,
          flexShrink: 0,
        }}
      >
        <span
          style={{
            width: 6,
            height: 6,
            borderRadius: "50%",
            background: isOnline ? "#52c41a" : "#8c8c8c",
          }}
        />
        {text}
      </span>
    );
  };

  // 左侧树只渲染当前筛选结果，颜色用于区分是否参与右侧轮巡。
  const treeData = filteredVideoList.map(video => ({
    title: (
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 8, width: "100%" }}>
        <span
          style={{
            color: checkedKeys.includes(video.id?.toString()) ? "#1677ff" : "#000",
            fontWeight: checkedKeys.includes(video.id?.toString()) ? 600 : 400,
            flex: 1,
            minWidth: 0,
            overflow: "hidden",
            textOverflow: "ellipsis",
            whiteSpace: "nowrap",
          }}
        >
          {video.videoName}
        </span>
        {renderOnlineStatus(video.isOnline)}
      </div>
    ),
    key: video.id?.toString(),
  }));

  // 不同宫格对应不同的网格布局。
  const getGridColumns = () => {
    if (layoutMode === 1)
      return "1fr";
    if (layoutMode === 4)
      return "repeat(2, 1fr)";
    return "repeat(3, 1fr)";
  };

  const getGridRows = () => {
    if (layoutMode === 1)
      return "1fr";
    if (layoutMode === 4)
      return "repeat(2, 1fr)";
    if (layoutMode === 9)
      return "repeat(3, 1fr)";
    return "repeat(2, 1fr)";
  };

  // 渲染单个视频卡片：包含播放器、失败态、截图按钮和视频名称。
  const renderVideoCard = (video, index) => {
    const playUrl = video ? playUrls[video.id?.toString()] : null;
    const playStatus = video ? playStatusMap[video.id?.toString()] : undefined;

    return (
      <div
        key={video?.id || index}
        ref={(node) => {
          if (video?.id) {
            videoCardRefs.current[video.id] = node;
          }
        }}
        style={{ display: "flex", flexDirection: "column", height: "100%", minHeight: 0, overflow: "hidden" }}
      >
        <div style={{ flex: 1, minHeight: 0, display: "flex", alignItems: "center", justifyContent: "center" }}>
          <Card
            size="small"
            bodyStyle={{
              padding: 0,
              height: "100%",
              width: "100%",
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              background: "#000",
            }}
            style={{ width: "100%", height: "100%", border: "1px solid #d9d9d9", borderRadius: 4, overflow: "hidden" }}
          >
            <div style={{ width: "100%", height: "100%", display: "flex", alignItems: "center", justifyContent: "center", background: "#000" }}>
              {video
                ? (
                    playStatus === "error"
                      ? (
                          <div
                            style={{
                              display: "flex",
                              flexDirection: "column",
                              alignItems: "center",
                              justifyContent: "center",
                              height: "100%",
                              color: "#ff4d4f",
                              gap: 8,
                            }}
                          >
                            <VideoCameraOutlined style={{ fontSize: 32 }} />
                            <span style={{ fontSize: 12 }}>视频加载失败</span>
                            <Button size="small" onClick={() => retryPlayUrl(video)}>重试</Button>
                          </div>
                        )
                      : playUrl
                        ? (
                            <div style={{ width: "100%", height: "100%", background: "#000" }}>
                              <Video
                                inline
                                height="100%"
                                width="100%"
                                source={playUrl}
                                isLive
                              />
                            </div>
                          )
                        : (
                            <div
                              style={{
                                display: "flex",
                                flexDirection: "column",
                                alignItems: "center",
                                justifyContent: "center",
                                height: "100%",
                                color: "#666",
                              }}
                            >
                              <VideoCameraOutlined style={{ fontSize: 32, marginBottom: 8 }} />
                              <span style={{ fontSize: 12 }}>加载中...</span>
                            </div>
                          )
                  )
                : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description="暂无视频" />}
            </div>
          </Card>
        </div>
        <div
          style={{
            height: 24,
            lineHeight: "24px",
            textAlign: "center",
            fontSize: 12,
            whiteSpace: "nowrap",
            overflow: "hidden",
            textOverflow: "ellipsis",
            flexShrink: 0,
          }}
        >
          {video ? video.videoName : "-"}
        </div>
      </div>
    );
  };

  return (
    <Page headerTitle="巡屏监控" isShowFooter={false} style={{ padding: "4px 16px", overflow: "hidden" }}>
      <div style={{ display: "flex", gap: 8, height: "calc(100vh - 100px)", overflow: "hidden" }}>
        {/* 左侧视频树：控制哪些视频参与右侧巡屏。 */}
        <Card
          title="视频列表"
          size="small"
          style={{ width: 280, minWidth: 280, maxWidth: 280, height: "100%" }}
          bodyStyle={{ height: "calc(100% - 56px)", overflow: "auto", padding: 8 }}
        >
          {filteredVideoList.length > 0
            ? (
                <Tree
                  checkable
                  blockNode
                  checkedKeys={checkedKeys}
                  onCheck={(keys) => {
                    const nextKeys = (Array.isArray(keys) ? keys : keys.checked).map(String);
                    setCheckedKeys(nextKeys);
                    setCurrentGroup(0);
                  }}
                  treeData={treeData}
                  style={{ background: "#fafafa", padding: 8, borderRadius: 4 }}
                />
              )
            : <Empty description={loadFailed ? "视频加载失败，请重试" : "暂无视频"} />}
        </Card>

        {/* 右侧巡屏主区域：包含搜索、宫格切换、视频网格和底部轮巡控制。 */}
        <Card
          style={{ flex: 1, height: "100%" }}
          bodyStyle={{ height: "100%", padding: 12, display: "flex", flexDirection: "column", overflow: "hidden" }}
        >
          {/* 搜索区：按视频名称和在线状态筛选左树与右侧轮巡集合。 */}
          <Form form={form} onFinish={handleSearch} style={{ display: "flex", gap: 16, marginBottom: 16, flexShrink: 0 }}>
            <Form.Item name="videoName" label="视频名称" style={{ marginBottom: 0 }}>
              <Input placeholder="请输入视频名称" />
            </Form.Item>
            <Form.Item name="isOnline" label="当前状态" style={{ marginBottom: 0 }}>
              <Select
                placeholder="请选择状态"
                options={IS_ONLINE_ENUM}
                fieldNames={{ label: "name", value: "bianma" }}
                style={{ width: 160 }}
              />
            </Form.Item>
            <Form.Item style={{ marginBottom: 0 }}>
              <Button type="primary" htmlType="submit" icon={<SearchOutlined />}>搜索</Button>
            </Form.Item>
            <Form.Item style={{ marginBottom: 0 }}>
              <Button onClick={handleReset} icon={<ReloadOutlined />}>重置</Button>
            </Form.Item>
          </Form>

          {/* 宫格切换区：修改宫格后会重新计算当前分组和自动轮巡状态。 */}
          <div style={{ display: "flex", alignItems: "center", gap: 16, marginTop: 10, flexShrink: 0 }}>
            <Radio.Group
              value={layoutMode}
              onChange={(e) => {
                const nextLayoutMode = e.target.value;
                setLayoutMode(nextLayoutMode);
                setCurrentGroup(0);
              }}
              optionType="button"
              buttonStyle="solid"
            >
              {LAYOUT_MODES.map(mode => (
                <Radio.Button key={mode.value} value={mode.value}>
                  {mode.label}
                </Radio.Button>
              ))}
            </Radio.Group>
          </div>

          {/* 视频网格区：按当前分组渲染参与轮巡的视频。 */}
          <div
            style={{
              flex: 1,
              display: "grid",
              gap: 8,
              marginTop: 12,
              gridTemplateColumns: getGridColumns(),
              gridTemplateRows: getGridRows(),
              minHeight: 0,
              overflow: "hidden",
            }}
          >
            {Array.from({ length: layoutMode }).map((_, index) => renderVideoCard(displayVideos[index], index))}
          </div>

          {/* 底部控制区：调整轮巡间隔、开始/停止轮巡、上一组/下一组。 */}
          <div
            style={{
              display: "flex",
              justifyContent: "center",
              alignItems: "center",
              gap: 16,
              padding: "8px 0",
              flexShrink: 0,
              borderTop: "1px solid #f0f0f0",
              marginTop: 8,
            }}
          >
            <div style={{ display: "flex", gap: 8 }}>
              <Button icon={<LeftOutlined />} onClick={handlePrevGroup} disabled={selectedVideos.length === 0}>上一组</Button>
              <Button icon={<RightOutlined />} onClick={handleNextGroup} disabled={selectedVideos.length === 0}>下一组</Button>
            </div>
          </div>
        </Card>
      </div>
    </Page>
  );
}

export default BatchPlay;
