<script setup lang="ts">
  import { PageWrapper } from '/@/components/Page';
  import OrganizationIdTree from '../../common/organizationIdTree/src/OrganizationIdTree.vue';
  import { onMounted, reactive, ref, unref, watch } from 'vue';
  import { Spin, Button, Pagination, Space, List } from 'ant-design-vue';
  import { cameraPage } from '/@/api/camera/cameraManager';
  import { CameraRecord } from '/@/api/camera/model/cameraModel';
  import { useFullscreen } from '@vueuse/core';
  import CameraDrawer from './CameraDrawer.vue';
  import { useDrawer } from '/@/components/Drawer';
  import { AccessMode, CameraPermission, PageMode } from './config.data';
  import SvgIcon from '/@/components/Icon/src/SvgIcon.vue';
  import { getStreamingPlayUrl } from '/@/api/camera/cameraManager';
  import { buildUUID } from '/@/utils/uuid';
  import { BasicVideoPlay, getVideoTypeByUrl } from '/@/components/Video';
  import { VideoJsPlayerOptions } from 'video.js';
  import { getBoundingClientRect } from '/@/utils/domUtils';
  import { Authority } from '/@/components/Authority';

  type CameraRecordItem = CameraRecord & {
    canPlay?: boolean;
    isTransform?: boolean;
    videoPlayerOptions?: VideoJsPlayerOptions;
  };

  const basicVideoPlayOptions: VideoJsPlayerOptions = {
    width: '100%' as unknown as number,
    height: '100%' as unknown as number,
    autoplay: true,
  };

  const emit = defineEmits(['switchMode']);
  const organizationIdTreeRef = ref(null);
  const videoContainer = ref<Nullable<HTMLDivElement>>(null);
  const activeKey = ref(PageMode.SPLIT_SCREEN_MODE);
  const cameraList = ref<CameraRecordItem[]>([]);
  const organizationId = ref<Nullable<string>>(null);
  const loading = ref(false);
  const pagination = reactive({
    page: 1,
    pageSize: 4,
    colNumber: 2,
    total: 0,
  });

  // 树形选择器
  const handleSelect = (orgId: string) => {
    organizationId.value = orgId;
    getCameraList();
  };

  const getCameraList = async () => {
    try {
      cameraList.value = [];
      loading.value = true;
      let { items, total } = await cameraPage({
        page: pagination.page,
        pageSize: pagination.pageSize,
        organizationId: unref(organizationId)!,
      });
      pagination.total = total;

      for (const item of items) {
        (item as CameraRecordItem).isTransform = false;
        (item as CameraRecordItem).videoPlayerOptions = {
          ...basicVideoPlayOptions,
        };
        beforeVideoPlay(item);
      }
      if (items.length < pagination.pageSize) {
        const fillArr: any = Array.from({ length: pagination.pageSize - items.length }).map(() => ({
          id: buildUUID(),
          placeholder: true,
        }));
        items = [...items, ...fillArr];
      }
      cameraList.value = items;
    } catch (error) {
    } finally {
      loading.value = false;
    }
  };

  const beforeVideoPlay = async (record: CameraRecordItem) => {
    if (record.accessMode === AccessMode.ManuallyEnter) {
      if (record.videoUrl) {
        (record as CameraRecordItem).videoPlayerOptions = {
          ...basicVideoPlayOptions,
          sources: [
            {
              src: record.videoUrl,
              type: getVideoTypeByUrl(record.videoUrl),
            },
          ],
        };
        record.isTransform = true;
      }
    }
    if (record.accessMode === AccessMode.Streaming) {
      try {
        const { data: { url } = { url: '' } } = await getStreamingPlayUrl(record.id!);
        const index = unref(cameraList).findIndex((item) => item.id === record.id);
        if (~index) {
          const oldRecord = unref(cameraList).at(index)!;
          unref(cameraList)[index] = {
            ...oldRecord,
            videoPlayerOptions: {
              ...basicVideoPlayOptions,
              sources: [
                {
                  src: url,
                  type: getVideoTypeByUrl(url),
                },
              ],
            },
            isTransform: true,
          };
        }
      } catch (error) {
      } finally {
        const index = unref(cameraList).findIndex((item) => item.id === record.id);
        if (~index) unref(cameraList)[index].isTransform = true;
      }
    }
  };

  const gridLayout = ref({ gutter: 1, column: 2 });

  const handleSwitchLayoutWay = (pageSize: number, layout: number) => {
    gridLayout.value = { gutter: 1, column: Math.sqrt(pageSize) };
    pagination.colNumber = layout;
    pagination.pageSize = pageSize;
    pagination.page = 1;
    getCameraList();
  };

  const { enter, isFullscreen } = useFullscreen(videoContainer);

  const handleFullScreen = () => {
    enter();
  };

  watch(isFullscreen, () => {
    activeKey.value = unref(isFullscreen) ? PageMode.FULL_SCREEN_MODE : PageMode.SPLIT_SCREEN_MODE;
  });

  const handleChangeMode = (activeKey: string) => {
    if (activeKey === PageMode.FULL_SCREEN_MODE) {
      handleFullScreen();
    } else if (activeKey === PageMode.LIST_MODE) {
      emit('switchMode', PageMode.LIST_MODE);
    }
  };

  const [registerDrawer, { openDrawer }] = useDrawer();

  const handleAddCamera = () => {
    openDrawer(true, {
      isUpdate: false,
    });
  };

  onMounted(() => {
    getCameraList();
  });

  const listEl = ref();
  onMounted(() => {
    const clientHeight = document.documentElement.clientHeight;
    const rect = getBoundingClientRect(unref(listEl)!.$el!) as DOMRect;
    // list pading top 8 maring-top 8 extra slot 56
    const listContainerMarginBottom = 16;
    const listContainerHeight = clientHeight - rect.top - listContainerMarginBottom;
    const listContainerEl = (unref(listEl)!.$el as HTMLElement).querySelector(
      '.ant-spin-container'
    ) as HTMLElement;
    listContainerEl && (listContainerEl.style.height = listContainerHeight + 'px');
  });
</script>

<template>
  <div>
    <PageWrapper dense contentFullHeight contentClass="flex">
      <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" />
      <section class="p-4 split-screen-mode flex flex-col flex-auto w-3/4 xl:w-4/5">
        <div class="p-3 bg-light-50 flex justify-between mb-4 dark:bg-dark-900">
          <div class="flex gap-4 cursor-pointer items-center">
            <div
              class="w-8 h-8 flex justify-center items-center"
              :style="{ color: pagination.colNumber === 1 ? '#1890ff' : '' }"
              @click="handleSwitchLayoutWay(1, 1)"
            >
              <SvgIcon class="text-2xl" prefix="iconfont" name="grid-one" />
            </div>
            <div
              class="w-8 h-8 flex justify-center items-center"
              :style="{ color: pagination.colNumber === 2 ? '#1890ff' : '' }"
              @click="handleSwitchLayoutWay(4, 2)"
            >
              <SvgIcon class="text-2xl" prefix="iconfont" name="grid-four" />
            </div>
            <div
              class="w-8 h-8 flex justify-center items-center"
              :style="{ color: pagination.colNumber === 3 ? '#1890ff' : '' }"
              @click="handleSwitchLayoutWay(9, 3)"
            >
              <SvgIcon class="text-2xl" prefix="iconfont" name="grid-nine" />
            </div>
            <div>
              <Pagination
                v-model:current="pagination.page"
                :total="pagination.total"
                :page-size="pagination.pageSize"
                :show-size-changer="false"
                @change="getCameraList"
                :simple="true"
                :show-quick-jumper="true"
                :show-total="(total) => `共 ${total} 条`"
              />
            </div>
          </div>
          <div class="flex items-center gap-4">
            <div class="flex">
              <Authority :value="CameraPermission.CREATE">
                <Button type="primary" @click="handleAddCamera">新增视频</Button>
              </Authority>
            </div>
            <Space>
              <Button type="primary" @click="handleChangeMode(PageMode.SPLIT_SCREEN_MODE)">
                分屏模式
              </Button>
              <Button type="primary" @click="handleChangeMode(PageMode.LIST_MODE)">
                列表模式
              </Button>
              <Button type="primary" @click="handleChangeMode(PageMode.FULL_SCREEN_MODE)">
                全屏
              </Button>
            </Space>
          </div>
        </div>
        <section ref="videoContainer" class="flex-auto">
          <List
            ref="listEl"
            :loading="loading"
            :data-source="cameraList"
            class="bg-light-50 w-full h-full dark:bg-dark-900 split-mode-list"
            :grid="gridLayout"
            :style="{ '--height': `${100 / pagination.colNumber}%` }"
          >
            <template #renderItem="{ item }">
              <List.Item>
                <div class="box-border w-full h-full p-1px">
                  <div
                    v-if="item.placeholder"
                    class="bg-black w-full h-full overflow-hidden relative"
                  ></div>
                  <div
                    v-if="!item.placeholder"
                    class="bg-black w-full h-full overflow-hidden relative video-container"
                  >
                    <Spin
                      class="!absolute top-1/2 left-1/2 transform -translate-1/2"
                      v-show="!item.isTransform"
                      :spinning="!item.isTransform"
                    />
                    <BasicVideoPlay v-if="item.isTransform" :options="item.videoPlayerOptions" />
                    <div
                      class="video-container-mask absolute top-0 left-0 z-50 text-lg w-full text-light-50 flex justify-center items-center"
                      style="height: 100%; background-color: rgba(0, 0, 0, 0.5)"
                    >
                      <span>{{ item.name }}</span>
                    </div>
                  </div>
                </div>
              </List.Item>
            </template>
          </List>
        </section>
      </section>
    </PageWrapper>
    <CameraDrawer @register="registerDrawer" @success="getCameraList" />
  </div>
</template>

<style scoped lang="less">
  .split-screen-mode:deep(.ant-tabs-bar) {
    margin-bottom: 0;
  }

  .split-screen-mode:deep(.ant-spin-nested-loading) {
    height: 100%;
  }

  .split-screen-mode:deep(.ant-spin-container) {
    height: 100% !important;
  }

  .video-container {
    .video-container-mask {
      opacity: 0;
      transition: opacity 0.5;
      pointer-events: none;
    }

    &:hover {
      .video-container-mask {
        opacity: 1;
      }

      .video-container-error-msk {
        color: #000;
      }
    }
  }

  .split-mode-list:deep(.ant-row) {
    width: 100%;
    height: 100%;
  }

  .split-mode-list:deep(.ant-list-item) {
    width: 100%;
    height: 100%;
  }

  .split-mode-list:deep(.ant-col) {
    width: 100%;
    height: 100%;
  }

  .split-mode-lis:deep(.ant-spin-container:fullscreen) {
    height: 100% !important;
  }
</style>
