<script setup lang="ts">
import type { LineAlarms, LineDevices, NdmDeviceResultVO, Station, VersionInfo } from '@/apis';
import { ThemeSwitch } from '@/components';
import { NDM_ALARM_STORE_ID, NDM_DEVICE_STORE_ID, NDM_STATION_STORE_ID } from '@/constants';
import { usePollingStore, useSettingStore } from '@/stores';
import { downloadByData, getAppEnvConfig, parseErrorFeedback, sleep } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { DeleteOutlined, ExportOutlined, ImportOutlined } from '@vicons/antd';
import { useEventListener } from '@vueuse/core';
import axios from 'axios';
import destr from 'destr';
import { isFunction } from 'es-toolkit';
import localforage from 'localforage';
import { NButton, NDivider, NDrawer, NDrawerContent, NDropdown, NFlex, NFormItem, NIcon, NInput, NInputNumber, NModal, NSwitch, NText, type DropdownOption } from 'naive-ui';
import { storeToRefs } from 'pinia';
import { onMounted, ref } from 'vue';
import { useRoute } from 'vue-router';

const route = useRoute();

const show = defineModel<boolean>('show', { default: false });

const settingsStore = useSettingStore();
const { menuCollpased, stationGridCols, debugModeEnabled, offlineDev } = storeToRefs(settingsStore);

const versionInfo = ref<VersionInfo>({ version: '', buildTime: '' });

const { mutate: getVersionInfo } = useMutation({
  mutationFn: async () => {
    const { data } = await axios.get<VersionInfo>(`/manifest.json?t=${Date.now()}`);
    return data;
  },
  onSuccess: (data) => {
    versionInfo.value = data;
  },
  onError: (error) => {
    console.error(error);
    const errorFeedback = parseErrorFeedback(error);
    window.$message.error(errorFeedback);
  },
});

const showDebugCodeModal = ref(false);
const debugCode = ref('');
const enableDebugMode = () => {
  const { debugCode: expectedDebugCode } = getAppEnvConfig();
  if (debugCode.value !== expectedDebugCode) {
    window.$message.error('调试授权码错误');
    return;
  }
  showDebugCodeModal.value = false;
  settingsStore.enableDebugMode();
};
const disableDebugMode = () => {
  showDebugCodeModal.value = false;
  settingsStore.disableDebugMode();
};
useEventListener('keydown', (event) => {
  const { ctrlKey, altKey, code } = event;
  if (ctrlKey && altKey && code === 'KeyD') {
    showDebugCodeModal.value = true;
  }
});

const expectToShowDebugCodeInput = ref(false);
const onModalAfterEnter = () => {
  expectToShowDebugCodeInput.value = !debugModeEnabled.value;
};
const onModalAfterLeave = () => {
  expectToShowDebugCodeInput.value = false;
  debugCode.value = '';
};

const pollingStore = usePollingStore();
const { pollingEnabled } = storeToRefs(pollingStore);
const onPollingEnabledUpdate = (enabled: boolean) => {
  if (enabled) {
    pollingStore.startPolling();
  } else {
    pollingStore.stopPolling();
  }
};

type IndexedDbStoreId = typeof NDM_STATION_STORE_ID | typeof NDM_DEVICE_STORE_ID | typeof NDM_ALARM_STORE_ID;
type IndexedDbStoreStates = {
  [NDM_STATION_STORE_ID]: { stations: Station[] };
  [NDM_DEVICE_STORE_ID]: { lineDevices: LineDevices };
  [NDM_ALARM_STORE_ID]: { lineAlarms: LineAlarms; unreadLineAlarms: LineAlarms };
};
const exportFromIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, options?: { errorMsg?: string }) => {
  const { errorMsg } = options ?? {};
  const data = await localforage.getItem<IndexedDbStoreStates[K]>(storeId);
  if (!data) {
    window.$message.error(errorMsg ?? '导出数据失败');
    return;
  }
  downloadByData(JSON.stringify(data, null, 2), `${storeId}.json`);
};
const importToIndexedDB = async <K extends IndexedDbStoreId>(storeId: K, options?: { successMsg?: string; errorMsg?: string }) => {
  const { successMsg, errorMsg } = options ?? {};
  const fileInput = document.createElement('input');
  fileInput.type = 'file';
  fileInput.accept = '.json';
  fileInput.click();
  fileInput.onchange = async () => {
    const file = fileInput.files?.[0];
    if (!file) {
      window.$message.error(errorMsg ?? '导入数据失败');
      return;
    }
    const reader = new FileReader();
    reader.readAsText(file, 'utf-8');
    reader.onload = async () => {
      const data = destr<IndexedDbStoreStates[K]>(reader.result as string);
      await localforage.setItem(storeId, data);
      window.$message.success(successMsg ?? '导入数据成功');
      await sleep(2000);
      window.location.reload();
    };
  };
};
const deleteFromIndexedDB = async (storeId: IndexedDbStoreId) => {
  await localforage.removeItem(storeId).catch((error) => {
    window.$message.error(`${error}`);
    return;
  });
  window.$message.success('删除成功');
  await sleep(2000);
  window.location.reload();
};

const exportDropdownOptions: DropdownOption[] = [
  {
    label: '导出车站',
    key: 'exportStations',
    onSelect: () => exportFromIndexedDB(NDM_STATION_STORE_ID),
  },
  {
    label: '导出设备',
    key: 'exportDevices',
    onSelect: () => exportFromIndexedDB(NDM_DEVICE_STORE_ID),
  },
  {
    label: '导出告警',
    key: 'exportAlarms',
    onSelect: () => exportFromIndexedDB(NDM_ALARM_STORE_ID),
  },
];
const importDropdownOptions: DropdownOption[] = [
  {
    label: '导入车站',
    key: 'importStations',
    onSelect: () => importToIndexedDB(NDM_STATION_STORE_ID),
  },
  {
    label: '导入设备',
    key: 'importDevices',
    onSelect: () => importToIndexedDB(NDM_DEVICE_STORE_ID),
  },
  {
    label: '导入告警',
    key: 'importAlarms',
    onSelect: () => importToIndexedDB(NDM_ALARM_STORE_ID),
  },
];
const deleteDropdownOptions: DropdownOption[] = [
  {
    label: '删除车站',
    key: 'deleteStations',
    onSelect: () => deleteFromIndexedDB(NDM_STATION_STORE_ID),
  },
  {
    label: '删除设备',
    key: 'deleteDevices',
    onSelect: () => deleteFromIndexedDB(NDM_DEVICE_STORE_ID),
  },
  {
    label: '删除告警',
    key: 'deleteAlarms',
    onSelect: () => deleteFromIndexedDB(NDM_ALARM_STORE_ID),
  },
];

const onSelectDropdownOption = (key: string, option: DropdownOption) => {
  const onSelect = option['onSelect'];
  if (isFunction(onSelect)) {
    onSelect();
  }
};

onMounted(() => {
  getVersionInfo();
});
</script>

<template>
  <NDrawer v-model:show="show" :width="560" :auto-focus="false">
    <NDrawerContent closable title="系统设置" :native-scrollbar="false">
      <NFlex vertical>
        <NDivider>主题</NDivider>
        <NFormItem label="深色模式" label-placement="left">
          <ThemeSwitch size="small" />
        </NFormItem>

        <NDivider>布局</NDivider>
        <NFormItem label="折叠菜单" label-placement="left">
          <NSwitch size="small" v-model:value="menuCollpased" />
        </NFormItem>
        <template v-if="route.path === '/station'">
          <NFormItem label="车站列数" label-placement="left">
            <NInputNumber v-model:value="stationGridCols" :min="1" :max="10" />
          </NFormItem>
        </template>

        <template v-if="debugModeEnabled">
          <NDivider title-placement="center">调试</NDivider>
          <NFormItem label="启用轮询" label-placement="left">
            <NSwitch size="small" :value="pollingEnabled" @update:value="onPollingEnabledUpdate" />
          </NFormItem>
          <NFormItem label="离线开发" label-placement="left">
            <NSwitch size="small" v-model:value="offlineDev" />
          </NFormItem>
          <NFormItem label="本地数据库" label-placement="left">
            <NFlex>
              <NDropdown trigger="click" :options="exportDropdownOptions" @select="onSelectDropdownOption">
                <NButton secondary size="small">
                  <template #icon>
                    <NIcon :component="ExportOutlined" />
                  </template>
                  <template #default>导出</template>
                </NButton>
              </NDropdown>
              <NDropdown trigger="click" :options="importDropdownOptions" @select="onSelectDropdownOption">
                <NButton secondary size="small">
                  <template #icon>
                    <NIcon :component="ImportOutlined" />
                  </template>
                  <template #default>导入</template>
                </NButton>
              </NDropdown>
              <NDropdown trigger="click" :options="deleteDropdownOptions" @select="onSelectDropdownOption">
                <NButton secondary size="small">
                  <template #icon>
                    <NIcon :component="DeleteOutlined" />
                  </template>
                  <template #default>删除</template>
                </NButton>
              </NDropdown>
            </NFlex>
          </NFormItem>
        </template>
      </NFlex>
      <template #footer>
        <NFlex vertical justify="flex-end" align="center" style="width: 100%; font-size: 12px; gap: 4px">
          <NText :depth="3">平台版本: {{ versionInfo.version }} ({{ versionInfo.buildTime }})</NText>
        </NFlex>
      </template>
    </NDrawerContent>
  </NDrawer>

  <NModal v-model:show="showDebugCodeModal" preset="dialog" type="info" @after-enter="onModalAfterEnter" @after-leave="onModalAfterLeave">
    <template #header>
      <NText v-if="!debugModeEnabled">请输入调试码</NText>
      <NText v-else>确认关闭调试模式</NText>
    </template>
    <template #default>
      <NInput v-if="expectToShowDebugCodeInput" v-model:value="debugCode" placeholder="输入调试码" @keyup.enter="enableDebugMode" />
    </template>
    <template #action>
      <NButton @click="showDebugCodeModal = false">取消</NButton>
      <NButton v-if="!debugModeEnabled" type="primary" @click="enableDebugMode">启用</NButton>
      <NButton v-else type="primary" @click="disableDebugMode">确认</NButton>
    </template>
  </NModal>
</template>

<style scoped lang="scss"></style>
