<template>
  <a-card :title="definition.title" :bordered="false">
    <template #extra>
      <a-space>
        <a-button @click="load">刷新</a-button>
        <a-button v-if="canCreate" type="primary" @click="openCreate">新增</a-button>
      </a-space>
    </template>
    <a-tree :data="tree" :loading="loading" :field-names="{ key: 'identity', title: 'name', children: 'children' }">
      <template #title="node">
        <a-space>
          {{ node.title }}
          <a-button v-if="canEdit" size="mini" @click.stop="openEdit(node)">编辑</a-button>
          <a-button v-if="canChangeStatus" size="mini" @click.stop="confirmStatus(node)">{{ node.status === 1 ? '停用' : '启用' }}</a-button>
          <a-button v-if="canArchive" size="mini" status="danger" @click.stop="confirmArchive(node)">归档</a-button>
        </a-space>
      </template>
    </a-tree>
  </a-card>
  <a-drawer :visible="formVisible" :title="editingIdentity ? `编辑${definition.title}` : `新增${definition.title}`" :width="480" @cancel="formVisible = false" @ok="save">
    <a-form :model="form" layout="vertical">
      <a-form-item v-for="field in definition.fields" :key="field.key" :label="field.label" :required="field.required">
        <a-input-number v-if="field.type === 'number' || field.type === 'money'" v-model="form[field.key]" :precision="field.type === 'money' ? 2 : 0" />
        <a-switch v-else-if="field.type === 'boolean'" v-model="form[field.key]" />
        <a-select v-else-if="field.type === 'identity'" v-model="form[field.key]" allow-clear allow-search>
          <a-option v-for="option in list.filter((item) => item.identity !== editingIdentity)" :key="option.identity" :value="option.identity">
            {{ option.name ?? option.menu_code ?? option.identity }}
          </a-option>
        </a-select>
        <a-input v-else v-model="form[field.key]" />
      </a-form-item>
    </a-form>
  </a-drawer>
</template>

<script setup lang="ts">
import { Message, Modal } from '@arco-design/web-vue';
import { computed, onMounted, reactive, ref } from 'vue';
import { resourceApi } from '@/api/resource';
import { buildResourcePayload, isMissingField } from '@/api/resource-form';
import type { ResourceUiDefinition } from '@/api/resources';
import { useUserStore } from '@/store';

type Node = Record<string, unknown> & {
  identity: string;
  parent_identity?: string;
  children: Node[];
};
const props = defineProps<{ definition: ResourceUiDefinition }>();
const userStore = useUserStore();
const loading = ref(false);
const list = ref<Node[]>([]);
const formVisible = ref(false);
const editingIdentity = ref('');
const form = reactive<Record<string, any>>({});
const rootAllowed = computed(
  () => props.definition.name !== 'platform_menu' || userStore.role === 'root',
);
const canCreate = computed(
  () => props.definition.canCreate && rootAllowed.value,
);
const canEdit = computed(() => props.definition.canEdit && rootAllowed.value);
const canChangeStatus = computed(
  () => props.definition.canChangeStatus && rootAllowed.value,
);
const canArchive = computed(
  () => props.definition.canArchive && rootAllowed.value,
);
const tree = computed(() => {
  const byIdentity = new Map<string, Node>();
  const roots: Node[] = [];
  for (const item of list.value)
    byIdentity.set(item.identity, { ...item, children: [] });
  for (const item of byIdentity.values()) {
    const parent = item.parent_identity
      ? byIdentity.get(item.parent_identity)
      : undefined;
    if (parent) parent.children.push(item);
    else roots.push(item);
  }
  return roots;
});

function reset(data?: Node) {
  for (const field of props.definition.fields) {
    const value = data?.[field.key];
    form[field.key] = value == null ? undefined : value;
  }
}

function confirmStatus(node: Node) {
  const status = node.status === 1 ? 2 : 1;
  Modal.warning({
    title: status === 1 ? '确认启用' : '确认停用',
    content: `确定要${status === 1 ? '启用' : '停用'}“${String(node.name ?? node.identity)}”吗？`,
    onOk: async () => {
      try {
        await resourceApi.updateStatus(
          props.definition.resource,
          node.identity,
          status,
        );
        Message.success('状态已更新');
        await load();
      } catch (error) {
        Message.error((error as Error).message);
      }
    },
  });
}

function openCreate() {
  editingIdentity.value = '';
  reset();
  formVisible.value = true;
}

function openEdit(node: Node) {
  editingIdentity.value = node.identity;
  reset(node);
  formVisible.value = true;
}

async function save() {
  if (
    props.definition.fields.some(
      (field) => field.required && isMissingField(form[field.key]),
    )
  ) {
    Message.warning('请填写必填字段');
    return;
  }
  try {
    const payload = buildResourcePayload(props.definition.fields, form);
    if (editingIdentity.value)
      await resourceApi.update(
        props.definition.resource,
        editingIdentity.value,
        payload,
      );
    else await resourceApi.create(props.definition.resource, payload);
    formVisible.value = false;
    await load();
  } catch (error) {
    Message.error((error as Error).message);
  }
}

function confirmArchive(node: Node) {
  Modal.warning({
    title: '确认归档',
    content: `归档“${String(node.name ?? node.identity)}”后，其历史数据仍会保留。`,
    onOk: async () => {
      try {
        await resourceApi.archive(props.definition.resource, node.identity);
        Message.success('已归档');
        await load();
      } catch (error) {
        Message.error((error as Error).message);
      }
    },
  });
}

async function load() {
  loading.value = true;
  try {
    list.value = (
      await resourceApi.list<Node>(props.definition.resource, 1, 500)
    ).list;
  } catch (error) {
    Message.error((error as Error).message);
  } finally {
    loading.value = false;
  }
}

onMounted(load);
</script>
