<script setup lang="ts">
import { SettingsDrawer, SyncCameraResultModal } from '@/components';
import { useLineStationsQuery, useStompClient, useVerifyUserQuery } from '@/composables';
import { LINE_ALARMS_QUERY_KEY, LINE_DEVICES_QUERY_KEY, LINE_STATIONS_MUTATION_KEY, LINE_STATIONS_QUERY_KEY, STATION_ALARMS_MUTATION_KEY, STATION_DEVICES_MUTATION_KEY } from '@/constants';
import { useAlarmStore, useSettingStore, useUserStore } from '@/stores';
import { parseErrorFeedback } from '@/utils';
import { useIsFetching, useIsMutating, useMutation } from '@tanstack/vue-query';
import { isCancel } from 'axios';
import { ChevronDownIcon, ChevronsLeftIcon, ChevronsRightIcon, ComputerIcon, KeyIcon, LogOutIcon, LogsIcon, MapPinIcon, SettingsIcon, SirenIcon } from 'lucide-vue-next';
import {
  NBadge,
  NButton,
  NDropdown,
  NFlex,
  NIcon,
  NLayout,
  NLayoutContent,
  NLayoutFooter,
  NLayoutHeader,
  NLayoutSider,
  NMenu,
  type DropdownOption,
  type DropdownProps,
  type MenuOption,
} from 'naive-ui';
import { storeToRefs } from 'pinia';
import { computed, h, ref, watchEffect, type Component, type VNode } from 'vue';
import { RouterLink, useRoute, useRouter } from 'vue-router';

const route = useRoute();
const router = useRouter();

const userStore = useUserStore();
const { userInfo } = storeToRefs(userStore);

const alarmStore = useAlarmStore();
const { unreadAlarmCount } = storeToRefs(alarmStore);

const settingStore = useSettingStore();
const { menuCollpased, offlineDev } = storeToRefs(settingStore);

const { syncCameraResult, afterCheckSyncCameraResult } = useStompClient();

useVerifyUserQuery();
useLineStationsQuery();

// 全局loading状态依赖于轮询query的queryKey以及相关的mutationKey
const queryingCount = useIsFetching({
  predicate: (query) => {
    const pollingKeys = [LINE_STATIONS_QUERY_KEY, LINE_DEVICES_QUERY_KEY, LINE_ALARMS_QUERY_KEY];
    const queryKey = query.options.queryKey;
    return !!queryKey && Array.isArray(queryKey) && pollingKeys.some((key) => queryKey.includes(key));
  },
});
const mutatingCount = useIsMutating({
  predicate: (mutation) => {
    const mutationKeys = [LINE_STATIONS_MUTATION_KEY, STATION_DEVICES_MUTATION_KEY, STATION_ALARMS_MUTATION_KEY];
    const mutationKey = mutation.options.mutationKey;
    return !!mutationKey && Array.isArray(mutationKey) && mutationKeys.some((key) => mutationKey.includes(key));
  },
});
const appLoading = computed(() => queryingCount.value + mutatingCount.value > 0);

const onToggleMenuCollapsed = () => {
  menuCollpased.value = !menuCollpased.value;
};

const menuOptions: MenuOption[] = [
  {
    label: () => h(RouterLink, { to: '/station' }, { default: () => '车站状态' }),
    key: '/station',
    icon: renderIcon(MapPinIcon),
  },
  {
    label: () => h(RouterLink, { to: '/device' }, { default: () => '设备诊断' }),
    key: '/device',
    icon: renderIcon(ComputerIcon),
  },
  {
    label: '设备告警',
    key: '/alarm',
    icon: renderIcon(SirenIcon),
    children: [
      {
        label: () => h(RouterLink, { to: '/alarm/alarm-log' }, { default: () => '设备告警记录' }),
        key: '/alarm/alarm-log',
      },
      {
        label: () => h(RouterLink, { to: '/alarm/alarm-ignore' }, { default: () => '告警忽略管理' }),
        key: '/alarm/alarm-ignore',
      },
    ],
  },
  {
    label: '系统日志',
    key: '/log',
    icon: renderIcon(LogsIcon),
    children: [
      {
        label: () => h(RouterLink, { to: '/log/vimp-log' }, { default: () => '视频平台日志' }),
        key: '/log/vimp-log',
      },
      {
        label: () => h(RouterLink, { to: '/log/call-log' }, { default: () => '上级调用日志' }),
        key: '/log/call-log',
      },
    ],
  },
  {
    label: () => h(RouterLink, { to: '/permission' }, { default: () => '权限管理' }),
    key: '/permission',
    show: userStore.isLamp,
    icon: renderIcon(KeyIcon),
  },
];

const dropdownOptions: DropdownOption[] = [
  {
    label: '退出登录',
    key: 'logout',
    icon: renderIcon(LogOutIcon),
    onClick: async () => {
      try {
        await userStore.userLogout();
        router.push({ path: '/login' });
      } catch (error) {
        console.error(error);
        window.$message.error('退出登录失败');
      }
    },
  },
];

const onSelectDropdownOption: DropdownProps['onSelect'] = (value: string, option: DropdownOption) => {
  if (typeof option['onClick'] === 'function') {
    option['onClick']();
  }
};

const showSettingsDrawer = ref(false);
const openSettingsDrawer = () => {
  showSettingsDrawer.value = true;
};

const routeToRoot = () => {
  router.push({ path: '/' });
};

const routeToAlarmPage = () => {
  alarmStore.clearUnreadAlarms();
  if (route.path !== '/alarm/alarm-log') {
    router.push({ path: '/alarm/alarm-log' });
  }
};

const { mutate: getUserInfo } = useMutation({
  mutationFn: async (params?: { signal?: AbortSignal }) => {
    const { signal } = params ?? {};
    await userStore.userGetInfo({ signal });
  },
  onError: (error) => {
    if (isCancel(error)) return;
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

// 判断是否为离线开发模式 决定是否自动发送获取用户信息请求
watchEffect((onCleanup) => {
  if (offlineDev.value) return;
  const abortController = new AbortController();
  getUserInfo({ signal: abortController.signal });
  onCleanup(() => abortController.abort());
});

function renderIcon(icon: Component): () => VNode {
  return () => h(NIcon, null, { default: () => h(icon) });
}
</script>

<template>
  <NLayout has-sider style="min-width: 1440px">
    <!-- 左侧菜单 -->
    <NLayoutSider bordered :collapsed="menuCollpased" collapse-mode="width" :collapsed-width="64" @update:collapsed="onToggleMenuCollapsed">
      <NFlex vertical justify="space-between" :size="0" style="height: 100%">
        <NMenu :collapsed="menuCollpased" :collapsed-width="64" :collapsed-icon-size="20" :value="route.path" :options="menuOptions" />
        <NButton block quaternary :focusable="false" @click="onToggleMenuCollapsed">
          <template #icon>
            <NIcon :component="menuCollpased ? ChevronsRightIcon : ChevronsLeftIcon" />
          </template>
        </NButton>
      </NFlex>
    </NLayoutSider>
    <!-- 主体内容区域 -->
    <NLayout>
      <NLayoutHeader bordered class="app-layout-header">
        <NFlex justify="space-between" align="center" :size="8" style="width: 100%; height: 100%">
          <NFlex align="center">
            <h3 style="margin: 0 0 0 16px; cursor: pointer" @click="routeToRoot">网络设备管理平台</h3>
            <NButton text size="tiny" :loading="appLoading"></NButton>
          </NFlex>
          <NFlex align="center" :size="0" style="height: 100%">
            <NDropdown trigger="hover" show-arrow :options="dropdownOptions" @select="onSelectDropdownOption">
              <NButton :focusable="false" quaternary icon-placement="right" style="height: 100%">
                <template #default>
                  <span>{{ userInfo?.nickName ?? '' }}</span>
                </template>
                <template #icon>
                  <NIcon :component="ChevronDownIcon" />
                </template>
              </NButton>
            </NDropdown>
            <NButton quaternary :focusable="false" style="height: 100%" @click="openSettingsDrawer">
              <template #icon>
                <NIcon :component="SettingsIcon" />
              </template>
            </NButton>
          </NFlex>
        </NFlex>
      </NLayoutHeader>
      <NLayoutContent class="app-layout-content">
        <RouterView />
      </NLayoutContent>
      <NLayoutFooter bordered class="app-layout-footer">
        <NFlex :align="'center'" style="height: 100%; margin: 0 16px">
          <NBadge :value="unreadAlarmCount">
            <NButton secondary strong @click="routeToAlarmPage">
              <template #icon>
                <NIcon :component="SirenIcon" />
              </template>
            </NButton>
          </NBadge>
        </NFlex>
      </NLayoutFooter>
    </NLayout>
  </NLayout>

  <SettingsDrawer v-model:show="showSettingsDrawer" />

  <SyncCameraResultModal :sync-camera-result="syncCameraResult" @after-leave="afterCheckSyncCameraResult" />
</template>

<style scoped lang="scss">
$layout-header-height: 48px;
$layout-footer-height: 48px;

.app-layout-header {
  height: $layout-header-height;
}

.app-layout-content {
  height: calc(100vh - $layout-header-height - $layout-footer-height);
}

.app-layout-footer {
  height: $layout-footer-height;
}
</style>
