<script setup lang="ts">
import type { VxeGridProps } from '#/adapter/vxe-table';
import { useVbenVxeGrid } from '#/adapter/vxe-table';
import {
  getNotificationConfigApi,
  updateNotificationConfigApi,
} from '#/api/core/notification';
import type { NotificationApi } from '#/api/core/notification';
import { Page } from '@vben/common-ui';
import dayjs from 'dayjs';
import JsonEitorVue from 'json-editor-vue';
import { Alert, Button, Card, Modal, Row, Col, Space, Tag, message } from 'ant-design-vue';
import { onActivated, ref, watch } from 'vue';

type SectionKey = NotificationApi.ConfigSectionKey;

function createDefaultSectionItem(section: SectionKey) {
  if (section === 'schedules') {
    return {
      cancelType: 0,
      cancelValue: 0,
      deltaTime: { ticks: '0' },
      fireTime: { ticks: '0' },
      id: 0,
      repeatInterval: 0,
      repeats: false,
      scheduleType: 0,
    } satisfies NotificationApi.ScheduleItem;
  }

  if (section === 'presentations') {
    return {
      id: 0,
      infos: [],
      titles: [],
    } satisfies NotificationApi.PresentationItem;
  }

  return {
    conditionId: 0,
    id: 0,
    presentationId: 0,
    scheduleId: 0,
  } satisfies NotificationApi.NoticeItem;
}

const currentConfig = ref<NotificationApi.NotificationConfig | null>(null);
const updatedAt = ref('');
const loading = ref(false);
const dirty = ref(false);

const editorOpen = ref(false);
const editorMode = ref<'create' | 'edit'>('create');
const editorSection = ref<SectionKey>('schedules');
const editorSourceIndex = ref(-1);
const editorValue = ref<any>(null);

const sectionTitles: Record<SectionKey, string> = {
  schedules: 'Schedules',
  presentations: 'Presentations',
  activeNotis: 'Active Notis',
  inactiveNotis: 'Inactive Notis',
};

const DOTNET_TICKS_AT_UNIX_EPOCH = 621355968000000000;
const TICKS_PER_MILLISECOND = 10000;

function cloneValue<T>(value: T): T {
  return JSON.parse(JSON.stringify(value)) as T;
}

function formatTime(value?: string) {
  return value ? dayjs(value).format('YYYY-MM-DD HH:mm:ss') : '-';
}

function parseDotNetTicks(value?: number | string) {
  if (value === '' || value == null) {
    return null;
  }

  try {
    const ticks = Number(String(value));
    const unixMilliseconds = (ticks - DOTNET_TICKS_AT_UNIX_EPOCH) / TICKS_PER_MILLISECOND;
    const date = dayjs(unixMilliseconds);
    return date.isValid() ? date : null;
  } catch {
    return null;
  }
}

function formatFireTicks(value?: number | string) {
  if (value === '' || value == null) {
    return '-';
  }

  const date = parseDotNetTicks(value);
  if (!date) {
    return String(value);
  }

  return `${String(value)} (${date.format('YYYY-MM-DD HH:mm:ss')})`;
}

function getScheduleFireTimePreview() {
  if (editorSection.value !== 'schedules') {
    return '';
  }

  const ticks = editorValue.value?.fireTime?.ticks;
  if (ticks === '' || ticks == null) {
    return '未配置 fireTime.ticks';
  }

  const date = parseDotNetTicks(ticks);
  if (!date) {
    return `无法解析 fireTime.ticks：${String(ticks)}`;
  }

  return `原始 ticks：${String(ticks)}，本地时间：${date.format('YYYY-MM-DD HH:mm:ss')}`;
}

function scheduleTypeText(value: number) {
  return value === 1 ? 'ExactTime' : 'Interval';
}

function cancelTypeText(value: number) {
  return value === 1 ? 'OnceOnline' : 'None';
}

const scheduleGridOptions: VxeGridProps<NotificationApi.ScheduleItem> = {
  columns: [
    { field: 'id', title: 'ID', width: 90 },
    {
      field: 'scheduleType',
      formatter: ({ cellValue }) => scheduleTypeText(cellValue),
      title: '类型',
      width: 120,
    },
    {
      field: 'deltaTime',
      formatter: ({ cellValue }) => cellValue?.ticks || '-',
      title: 'delta ticks',
      minWidth: 160,
    },
    {
      field: 'fireTime',
      formatter: ({ cellValue }) => formatFireTicks(cellValue?.ticks),
      title: 'fire ticks',
      minWidth: 320,
    },
    { field: 'repeats', title: '重复', width: 90 },
    {
      field: 'cancelType',
      formatter: ({ cellValue }) => cancelTypeText(cellValue),
      title: '取消类型',
      width: 120,
    },
    { fixed: 'right', slots: { default: 'scheduleOperation' }, title: '操作', width: 160 },
  ],
  data: [],
  height: 'auto',
  minHeight: 360,
  pagerConfig: { enabled: false },
  rowConfig: { isHover: true },
};

const presentationGridOptions: VxeGridProps<NotificationApi.PresentationItem> = {
  columns: [
    { field: 'id', title: 'ID', width: 90 },
    {
      field: 'titles',
      formatter: ({ cellValue }) => (Array.isArray(cellValue) ? cellValue.length : 0),
      title: 'Title 数量',
      width: 120,
    },
    {
      field: 'infos',
      formatter: ({ cellValue }) => (Array.isArray(cellValue) ? cellValue.length : 0),
      title: 'Info 数量',
      width: 120,
    },
    {
      field: 'titlePreview',
      formatter: ({ row }) => row.titles?.map((item: any) => `${item.language}:${item.locText}`).join(' | ') || '-',
      title: '标题预览',
      minWidth: 280,
    },
    { fixed: 'right', slots: { default: 'presentationOperation' }, title: '操作', width: 160 },
  ],
  data: [],
  height: 'auto',
  minHeight: 360,
  pagerConfig: { enabled: false },
  rowConfig: { isHover: true },
};

const activeGridOptions: VxeGridProps<NotificationApi.NoticeItem> = {
  columns: [
    { field: 'id', title: 'ID', width: 90 },
    { field: 'scheduleId', title: 'Schedule ID', width: 120 },
    { field: 'conditionId', title: 'Condition ID', width: 120 },
    { field: 'presentationId', title: 'Presentation ID', width: 140 },
    { fixed: 'right', slots: { default: 'activeOperation' }, title: '操作', width: 160 },
  ],
  data: [],
  height: 'auto',
  minHeight: 360,
  pagerConfig: { enabled: false },
  rowConfig: { isHover: true },
};

const inactiveGridOptions: VxeGridProps<NotificationApi.NoticeItem> = {
  columns: [
    { field: 'id', title: 'ID', width: 90 },
    { field: 'scheduleId', title: 'Schedule ID', width: 120 },
    { field: 'conditionId', title: 'Condition ID', width: 120 },
    { field: 'presentationId', title: 'Presentation ID', width: 140 },
    { fixed: 'right', slots: { default: 'inactiveOperation' }, title: '操作', width: 160 },
  ],
  data: [],
  height: 'auto',
  minHeight: 360,
  pagerConfig: { enabled: false },
  rowConfig: { isHover: true },
};

const [ScheduleGrid, ScheduleGridApi] = useVbenVxeGrid({ gridOptions: scheduleGridOptions });
const [PresentationGrid, PresentationGridApi] = useVbenVxeGrid({ gridOptions: presentationGridOptions });
const [ActiveGrid, ActiveGridApi] = useVbenVxeGrid({ gridOptions: activeGridOptions });
const [InactiveGrid, InactiveGridApi] = useVbenVxeGrid({ gridOptions: inactiveGridOptions });

function syncGridData(config: NotificationApi.NotificationConfig | null) {
  ScheduleGridApi.setGridOptions({ data: config?.schedules || [] });
  PresentationGridApi.setGridOptions({ data: config?.presentations || [] });
  ActiveGridApi.setGridOptions({ data: config?.activeNotis || [] });
  InactiveGridApi.setGridOptions({ data: config?.inactiveNotis || [] });
}

watch(
  currentConfig,
  (config) => {
    syncGridData(config);
  },
  { deep: true, immediate: true },
);

async function loadConfig() {
  loading.value = true;
  try {
    const state = await getNotificationConfigApi();
    currentConfig.value = cloneValue(state.config);
    updatedAt.value = state.updated_at;
    dirty.value = false;
  } finally {
    loading.value = false;
  }
}

function setSectionItems(section: SectionKey, items: Array<any>) {
  if (!currentConfig.value) {
    return;
  }

  currentConfig.value = {
    ...currentConfig.value,
    [section]: items,
  } as NotificationApi.NotificationConfig;
  dirty.value = true;
}

function getSectionItems(section: SectionKey) {
  return (currentConfig.value?.[section] as Array<any>) || [];
}

function getDefaultSectionItem(section: SectionKey) {
  return cloneValue(createDefaultSectionItem(section));
}

function openCreateEditor(section: SectionKey) {
  editorMode.value = 'create';
  editorSection.value = section;
  editorSourceIndex.value = -1;
  editorValue.value = getDefaultSectionItem(section);
  editorOpen.value = true;
}

function openEditEditor(section: SectionKey, row: any, index: number) {
  editorMode.value = 'edit';
  editorSection.value = section;
  editorSourceIndex.value = index;
  editorValue.value = cloneValue(row);
  editorOpen.value = true;
}

async function persistConfig(action: 'create' | 'delete' | 'update', nextConfig: NotificationApi.NotificationConfig) {
  const response = await updateNotificationConfigApi(nextConfig);
  currentConfig.value = cloneValue(response.config);
  updatedAt.value = response.updated_at;
  dirty.value = false;
}

async function saveEditor() {
  const parsedValue =
    typeof editorValue.value === 'string'
      ? JSON.parse(editorValue.value)
      : cloneValue(editorValue.value);
  const nextConfig = cloneValue(currentConfig.value);
  const items = [...getSectionItems(editorSection.value)];

  if (editorMode.value === 'create') {
    items.push(parsedValue);
    setSectionItems(editorSection.value, items);
    message.success(`${sectionTitles[editorSection.value]} 已加入待保存变更`);
  } else {
    if (editorSourceIndex.value < 0) {
      return;
    }
    items.splice(editorSourceIndex.value, 1, parsedValue);
    setSectionItems(editorSection.value, items);
    message.success(`${sectionTitles[editorSection.value]} 已加入待保存变更`);
  }

  editorOpen.value = false;
}

function handleDelete(section: SectionKey, index: number) {
  Modal.confirm({
    content: `确认删除 ${sectionTitles[section]} 的这条配置吗？删除后需要点击“保存配置”才会提交到服务端。`,
    title: '删除确认',
    async onOk() {
      const items = [...getSectionItems(section)];
      items.splice(index, 1);
      setSectionItems(section, items);
      message.success(`${sectionTitles[section]} 已加入待保存变更`);
    },
  });
}

async function saveAllConfig() {
  if (!currentConfig.value) {
    return;
  }

  loading.value = true;
  try {
    await persistConfig('update', cloneValue(currentConfig.value));
    message.success('Notification 配置保存成功');
  } finally {
    loading.value = false;
  }
}

function reloadConfig() {
  Modal.confirm({
    content: dirty.value
      ? '当前有未保存修改，确认重新从服务端加载并覆盖本地草稿吗？'
      : '确认重新从服务端加载当前配置吗？',
    title: '重新加载配置',
    async onOk() {
      await loadConfig();
      message.success('已重新加载服务端配置');
    },
  });
}

void loadConfig();

onActivated(async () => {
  await loadConfig();
});
</script>

<template>
  <Page auto-content-height>
    <Card class="mb-5" title="客户端 Notification 配置">
      <Space>
        <Button :disabled="!dirty" :loading="loading" type="primary" @click="saveAllConfig">
          保存配置
        </Button>
        <Button :loading="loading" @click="reloadConfig">重新加载</Button>
        <Tag color="blue">当前配置已切换为服务端接口读写</Tag>
        <Tag :color="dirty ? 'orange' : 'green'">
          {{ dirty ? '存在未保存修改' : '已与服务端同步' }}
        </Tag>
        <Tag color="gold">最后更新时间：{{ formatTime(updatedAt) }}</Tag>
      </Space>
      <div class="mt-4">
        <Alert
          message="当前页面只提供查询与更新接口能力。新增、编辑、删除都会先写入本地草稿，点击“保存配置”后才会以完整 JSON 提交到服务端。"
          type="info"
        />
      </div>
    </Card>

    <Row :gutter="16">
      <Col :span="24">
        <Card class="mb-5" title="Schedules">
          <template #extra>
            <Button size="small" type="primary" @click="openCreateEditor('schedules')">新增</Button>
          </template>
          <ScheduleGrid>
            <template #scheduleOperation="{ row, rowIndex }">
              <Space>
                <Button size="small" type="primary" @click="openEditEditor('schedules', row, rowIndex)">编辑</Button>
                <Button danger size="small" @click="handleDelete('schedules', rowIndex)">删除</Button>
              </Space>
            </template>
          </ScheduleGrid>
        </Card>
      </Col>

      <Col :span="24">
        <Card class="mb-5" title="Presentations">
          <template #extra>
            <Button size="small" type="primary" @click="openCreateEditor('presentations')">新增</Button>
          </template>
          <PresentationGrid>
            <template #presentationOperation="{ row, rowIndex }">
              <Space>
                <Button size="small" type="primary" @click="openEditEditor('presentations', row, rowIndex)">编辑</Button>
                <Button danger size="small" @click="handleDelete('presentations', rowIndex)">删除</Button>
              </Space>
            </template>
          </PresentationGrid>
        </Card>
      </Col>

      <Col :span="24">
        <Card class="mb-5" title="Active Notis">
          <template #extra>
            <Button size="small" type="primary" @click="openCreateEditor('activeNotis')">新增</Button>
          </template>
          <ActiveGrid>
            <template #activeOperation="{ row, rowIndex }">
              <Space>
                <Button size="small" type="primary" @click="openEditEditor('activeNotis', row, rowIndex)">编辑</Button>
                <Button danger size="small" @click="handleDelete('activeNotis', rowIndex)">删除</Button>
              </Space>
            </template>
          </ActiveGrid>
        </Card>
      </Col>

      <Col :span="24">
        <Card title="Inactive Notis">
          <template #extra>
            <Button size="small" type="primary" @click="openCreateEditor('inactiveNotis')">新增</Button>
          </template>
          <InactiveGrid>
            <template #inactiveOperation="{ row, rowIndex }">
              <Space>
                <Button size="small" type="primary" @click="openEditEditor('inactiveNotis', row, rowIndex)">编辑</Button>
                <Button danger size="small" @click="handleDelete('inactiveNotis', rowIndex)">删除</Button>
              </Space>
            </template>
          </InactiveGrid>
        </Card>
      </Col>
    </Row>

    <Modal
      v-model:open="editorOpen"
      :confirm-loading="loading"
      :title="`${editorMode === 'create' ? '新增' : '编辑'} ${sectionTitles[editorSection]}`"
      width="980px"
      @ok="saveEditor"
    >
      <Alert
        v-if="editorSection === 'schedules'"
        class="mb-4"
        message="fireTime 预览"
        type="info"
      >
        <template #description>
          {{ getScheduleFireTimePreview() }}
        </template>
      </Alert>

      <JsonEitorVue v-model="editorValue" v-bind="{}" class="h-[600px] w-full" />
    </Modal>
  </Page>
</template>