<script lang="ts" setup>
import type { Sortable } from 'sortablejs';

import { computed, nextTick, onUnmounted, ref, watch } from 'vue';

import { HolderOutlined } from '@ant-design/icons-vue';
import { Button, Modal } from 'ant-design-vue';

import type { ExportFieldMeta } from '#/views/business/order/product-order/config/exportFields';
import { buildDefaultOrderedKeys } from '#/views/business/order/product-order/utils/exportFieldOrder';

defineOptions({
  name: 'ProductOrderExportFieldSortModal',
});

const props = defineProps<{
  open: boolean;
  orderedKeys: string[];
  selectedKeys: string[];
  fieldMeta: ExportFieldMeta[];
  granularity: 'order' | 'item';
}>();

const emit = defineEmits<{
  (e: 'update:open', value: boolean): void;
  (e: 'confirm', keys: string[]): void;
}>();

const listRef = ref<HTMLElement | null>(null);
const draftKeys = ref<string[]>([]);
let sortable: Sortable | null = null;

const labelMap = computed(
  () => new Map(props.fieldMeta.map((f) => [f.key, f.label])),
);

const draftItems = computed(() =>
  draftKeys.value.map((key) => ({
    key,
    label: labelMap.value.get(key) ?? key,
  })),
);

function destroySortable() {
  sortable?.destroy();
  sortable = null;
}

async function initSortable() {
  destroySortable();
  await nextTick();
  if (!listRef.value || !props.open) {
    return;
  }
  const mod = await import(
    // @ts-expect-error sortablejs modular esm path
    'sortablejs/modular/sortable.complete.esm.js'
  );
  sortable = mod.default.create(listRef.value, {
    animation: 200,
    handle: '.drag-handle',
    ghostClass: 'export-field-sort-item--ghost',
    onEnd() {
      if (!listRef.value) {
        return;
      }
      const keys: string[] = [];
      listRef.value.querySelectorAll('[data-key]').forEach((el) => {
        const key = el.getAttribute('data-key');
        if (key) {
          keys.push(key);
        }
      });
      draftKeys.value = keys;
    },
  });
}

watch(
  () => props.open,
  (open) => {
    if (open) {
      draftKeys.value = [...props.orderedKeys];
      void initSortable();
    } else {
      destroySortable();
    }
  },
);

onUnmounted(() => {
  destroySortable();
});

function handleCancel() {
  emit('update:open', false);
}

function handleConfirm() {
  emit('confirm', [...draftKeys.value]);
  emit('update:open', false);
}

function handleReset() {
  draftKeys.value = buildDefaultOrderedKeys(
    props.selectedKeys,
    props.granularity,
  );
  void initSortable();
}
</script>

<template>
  <Modal
    :open="open"
    title="字段排序"
    width="480px"
    ok-text="确认"
    cancel-text="取消"
    @cancel="handleCancel"
    @ok="handleConfirm"
  >
    <div class="mb-3 text-xs text-muted-foreground">
      拖拽左侧手柄调整 Excel 导出列顺序；金额类字段默认会聚合在一起。
    </div>
    <div
      ref="listRef"
      class="max-h-[360px] overflow-y-auto rounded-md border border-border"
    >
      <div
        v-for="item in draftItems"
        :key="item.key"
        :data-key="item.key"
        class="export-field-sort-item flex items-center gap-2 border-b border-border px-3 py-2 last:border-b-0"
      >
        <HolderOutlined class="drag-handle cursor-grab text-muted-foreground" />
        <span class="text-sm">{{ item.label }}</span>
      </div>
    </div>
    <div class="mt-3">
      <Button size="small" @click="handleReset">重置为默认顺序</Button>
    </div>
  </Modal>
</template>

<style scoped>
.export-field-sort-item--ghost {
  opacity: 0.5;
  background: hsl(var(--muted));
}
</style>
