<template>
  <Page class="h-full w-full">
    <!--  设备分组区域  -->
    <div class="flex h-full gap-[8px]">
      <ChannelTree class="h-[83vh] w-[300px]" @check="onNodeChecked" />

      <!--  设备分组区域  -->
      <div class="bg-background flex-1">
        <div class="video-play-area flex h-[calc(100%-30px)] flex-wrap">
          <div
            v-for="i in playerNum"
            :style="playerStyle"
            class="player"
            :class="`layer-${i} ${currentSelectPlayerIndex == i ? selected : ''}`"
            @click="playerSelect(i)"
          >
            <video
              style="width: 100%; height: 100%"
              :ref="setItemRef"
              muted
              autoplay
            ></video>
          </div>
        </div>
        <div class="player-area flex h-[30px] gap-[5px]">
          <div @click="onPlayerNumChanged(1)" class="h-[20px] w-[20px]">
            <Svg1FrameIcon style="width: 100%; height: 100%" />
          </div>
          <div @click="onPlayerNumChanged(2)" class="h-[20px] w-[20px]">
            <Svg4FrameIcon style="width: 100%; height: 100%" />
          </div>
          <div @click="onPlayerNumChanged(3)" class="h-[20px] w-[20px]">
            <Svg9FrameIcon style="width: 100%; height: 100%" />
          </div>
          <div @click="onPlayerNumChanged(4)" class="h-[20px] w-[20px]">
            <Svg16FrameIcon style="width: 100%; height: 100%" />
          </div>
        </div>
      </div>
    </div>
  </Page>
</template>

<script lang="ts" setup>
import { onMounted, onUnmounted, ref, toRaw } from 'vue';
import { Page } from '@vben/common-ui';
import ChannelTree from './channel-tree.vue';
import mpegts from 'mpegts.js';
import { message } from 'ant-design-vue';
import { addStreamProxy } from '#/api/sis/stream';
import {
  Svg16FrameIcon,
  Svg1FrameIcon,
  Svg4FrameIcon,
  Svg9FrameIcon,
} from '@vben/icons';

const selected = 'selected';

const itemRefs = ref<HTMLVideoElement[]>([]);
const setItemRef = (el: any) => {
  if (el) {
    itemRefs.value.push(el);
  }
};

/**
 * 屏幕播放器数量
 */
const playerNum = ref(1);
/**
 * 屏幕播放器样式
 */
const playerStyle = ref({
  width: '100%',
  height: '100%',
});
const currentSelectPlayerIndex = ref(-1);

function playerSelect(index: number) {
  if (index === currentSelectPlayerIndex.value) {
    currentSelectPlayerIndex.value = -1;
    return;
  }
  currentSelectPlayerIndex.value = index;
}

/**
 * 播放器数量
 * @param val
 */
function onPlayerNumChanged(val: number) {
  // 1个屏幕
  const changeBeforeNum = playerNum.value;
  let changeNum = 1;
  if (val === 1) {
    playerStyle.value = {
      width: '100%',
      height: '100%',
    };
  }
  // 4个屏幕 2*2
  else if (val === 2) {
    playerStyle.value = {
      width: '50%',
      height: '50%',
    };
    changeNum = 4;
  }
  // 9个屏幕 3*3
  else if (val === 3) {
    playerStyle.value = {
      width: '33.33%',
      height: '33.33%',
    };
    changeNum = 9;
  }
  // 16个屏幕 4*4
  else {
    playerStyle.value = {
      width: '25%',
      height: '25%',
    };
    changeNum = 16;
  }
  playerNum.value = changeNum;
  // 缩小布局
  if (changeBeforeNum > changeNum) {
    const playerArr = [];
    for (let i = 0; i < playerList.length; i++) {
      const playerBox = playerList[i];
      if (playerBox) {
        playerArr.push(playerBox);
      }
      playerList[i] = null;
    }
    for (let i = 0; i < playerArr.length; i++) {
      const play = playerArr[i];
      if (i < changeNum) {
        // 获取播放元素
        changeElPlayer(play, i);
      } else {
        closePlayVieo(play.player);
      }
    }
  }
}

/**
 * 处理带有子节点的数据
 * @param node
 * @param newNode
 */
function handleParentNoe(node: any, newNode: any[] = []) {
  if (node.children && node.children.length >= 1) {
    node.children.forEach((item: any) => {
      if (item.level === 2) {
        newNode.push(toRaw(item.data));
      }
      if (item.children && item.children.length >= 1) {
        handleParentNoe(item.children, newNode);
      }
    });
  }
}

// 播放器数据, 每一个位置代表页面上行的一个矩形
const playerList: any[] = [];

/**
 * 节点选中时间处理
 * @param _val 选中节点id
 * @param checked 是否选中
 * @param node 节点数据
 */
function onNodeChecked(
  _val: any,
  { checked, node }: { checked: boolean; node: any },
) {
  // 此次操作需要新增或者删除节点
  let checkNode: any = [];
  if (node.level === 1) {
    handleParentNoe(node, checkNode);
  } else {
    checkNode.push(toRaw(node.data));
  }
  // 新增
  if (checked) {
    /**
     * 如果当前页面有选择播放未知，并且播放视频只有一个，则播放到制定位置
     */
    if (currentSelectPlayerIndex.value !== -1 && checkNode.length == 1) {
      doPlayer(checkNode[0], currentSelectPlayerIndex.value - 1);
    }
    // 批量播放 currentSelectPlayerIndex 将不再生效
    else {
      // 如果此次播放数量小于当前播能播放
      const freeArr: number[] = []; // 空闲播放器数量
      for (let i = 0; i < playerNum.value; i++) {
        const playerData = playerList[i];
        if (!playerData) {
          freeArr.push(i);
        }
      }
      // 要播放的视频数量，小于等于空闲播放器数量，则填充空闲即可
      if (checkNode.length <= freeArr.length) {
        for (let j = 0; j < checkNode.length; j++) {
          doPlayer(checkNode[j], freeArr[j]);
        }
      }
      // 直接覆盖原有的播放视频
      else {
        for (let i = 0; i < playerNum.value; i++) {
          doPlayer(checkNode[i], i);
        }
      }
    }
  }
  // 删除
  else {
    checkNode.forEach((item: any) => {
      for (let i = 0; i < playerNum.value; i++) {
        const player = playerList[i];
        if (player && player.data.id === item.id) {
          closePlayer(i);
        }
      }
    });
  }
}

function changeElPlayer(playerInfo: any, index: number) {
  const playerData = playerInfo.data;
  const oldPlayer = playerInfo.player;
  if (oldPlayer) {
    closePlayVieo(oldPlayer);
  }
  const videoConfig = {
    type: 'flv',
    url: playerData.url,
    isLive: true,
    hasAudio: false,
    hasVideo: true,
    enableWorker: true, // 启用分离的线程进行转码
    enableStashBuffer: false, // 关闭IO隐藏缓冲区
    stashInitialSize: 256, // 减少首帧显示等待时长
  };
  const playerConfig = {
    enableErrorRecover: true, // 启用错误恢复
    autoCleanupMaxBackwardDuration: 30,
    autoCleanupMinBackwardDuration: 10,
  };
  const player = mpegts.createPlayer(videoConfig, playerConfig);
  const videoElement = itemRefs.value[index];
  if (videoElement) {
    player.attachMediaElement(videoElement);
    player.load();
    player.play();
    playerList[index] = {
      player,
      data: playerData,
    };
  } else {
    console.log('视频播放元素获取异常');
  }
}

/**
 * 开始播放视频流
 * @param nodeData 播放的节点数据
 * @param index 播放器的索引信息
 */
function doPlayer(nodeData: any, index: number = 0) {
  console.log('index=', index);
  if (mpegts.isSupported()) {
    let params = {};
    // if (nodeData.nvrIp) {
    //   params = {
    //     videoIp: nodeData.nvrIp,
    //     videoPort: nodeData.nvrPort,
    //     factoryNo: nodeData.nvrFactoryNo,
    //     account: nodeData.nvrAccount,
    //     pwd: nodeData.nvrPwd,
    //     channelId: nodeData.nvrChannelNo,
    //   };
    // } else {
      params = {
        videoIp: nodeData.deviceIp,
        videoPort: nodeData.devicePort,
        factoryNo: nodeData.factoryNo,
        account: nodeData.deviceAccount,
        pwd: nodeData.devicePwd,
        channelId: nodeData.channelNo,
      };
    // }
    addStreamProxy(params).then((res) => {
      const url = res.wsFlv;
      // 将url 绑定到 nodeData
      nodeData.url = url;
      closePlayer(index);
      const videoConfig = {
        type: 'flv',
        url: url,
        isLive: true,
        hasAudio: false,
        hasVideo: true,
        enableWorker: true, // 启用分离的线程进行转码
        enableStashBuffer: false, // 关闭IO隐藏缓冲区
        stashInitialSize: 256, // 减少首帧显示等待时长
      };
      const playerConfig = {
        enableErrorRecover: true, // 启用错误恢复
        autoCleanupMaxBackwardDuration: 30,
        autoCleanupMinBackwardDuration: 10,
      };
      const player = mpegts.createPlayer(videoConfig, playerConfig);
      const videoElement = itemRefs.value[index];
      if (videoElement) {
        player.attachMediaElement(videoElement);
        player.load();
        player.play();
        playerList[index] = {
          player,
          data: nodeData,
        };
      } else {
        console.log('视频播放元素获取异常');
      }
    });
  } else {
    message.error('浏览器不支持播放');
  }
}

function closePlayVieo(plInfo: any) {
  if (plInfo) {
    try {
      plInfo.pause(); // 暂停
      plInfo.unload(); // 卸载
      plInfo.destroy(); // 销毁
    } catch (e) {
      console.log('播放器关闭失败，e=', e);
    }
  }
}

function closePlayer(index: number) {
  // 如果播放器存在，尝试关闭
  const pData = playerList[index];
  if (pData) {
    try {
      const player = pData.player;
      player.pause(); // 暂停
      player.unload(); // 卸载
      player.destroy(); // 销毁
      playerList[index] = null;
    } catch (e) {
      console.log('播放器关闭失败，e=', e);
    }
  }
}

onMounted(() => {
  // 初始化不加载任何视频
});

onUnmounted(() => {
  for (let i = 0; i < playerList.length; i++) {
    closePlayer(i);
  }
});
</script>

<style scoped>
.player {
  border: 1px solid #e4e4e7;
  cursor: pointer;

  video {
    width: 100%;
    height: 100%;
    object-fit: fill;
  }
}

.player.selected {
  border: 2px solid deepskyblue;
}

.player-area {
  display: flex;
  align-items: center;
  cursor: pointer;
}
</style>
