<script setup lang="ts">
import { computed, nextTick, provide, ref, watch } from 'vue';
import { ElMessageBox } from 'element-plus';
import {
  fetchCreateRequirementModule,
  fetchDeleteRequirementModule,
  fetchGetRequirementModuleTree,
  fetchUpdateRequirementModule
} from '@/service/api';
import { useCurrentProduct } from '../../shared/use-current-product';
import ModuleTreeNode from './module-tree-node.vue';

defineOptions({ name: 'RequirementModuleTree' });

interface Props {
  requirementTree?: Api.Product.Requirement[];
}

const props = withDefaults(defineProps<Props>(), {
  requirementTree: () => []
});

interface Emits {
  (e: 'select', moduleId: string | undefined): void;
  (e: 'refresh'): void;
}

const emit = defineEmits<Emits>();

const { currentObjectId } = useCurrentProduct();

const loading = ref(false);
const moduleTree = ref<Api.Product.RequirementModule[]>([]);
const selectedModuleId = ref<string | undefined>(undefined);

const rootModule = computed<Api.Product.RequirementModule | null>(() => {
  if (moduleTree.value.length === 0) return null;
  return moduleTree.value[0];
});

const editingNodeId = ref<string | undefined>(undefined);
const editingName = ref('');

const addingChildParentId = ref<string | undefined>(undefined);
const newChildModuleName = ref('');

const collapsedModuleIds = ref(new Set<string>());

function handleToggleCollapse(moduleId: string) {
  const set = collapsedModuleIds.value;
  if (set.has(moduleId)) {
    set.delete(moduleId);
  } else {
    set.add(moduleId);
  }
  collapsedModuleIds.value = new Set(set);
}

provide('collapsedModuleIds', collapsedModuleIds);
provide('toggleCollapse', handleToggleCollapse);

const moduleRequirementCountMap = computed(() => {
  const countMap = new Map<string, number>();

  function countRequirementsByModule(nodes: Api.Product.Requirement[]): void {
    for (const node of nodes) {
      const currentCount = countMap.get(node.moduleId) || 0;
      countMap.set(node.moduleId, currentCount + 1);
      if (node.children?.length) {
        countRequirementsByModule(node.children);
      }
    }
  }

  if (props.requirementTree?.length) {
    countRequirementsByModule(props.requirementTree);
  }

  return countMap;
});

async function loadModuleTree() {
  if (!currentObjectId.value) {
    moduleTree.value = [];
    return;
  }

  loading.value = true;

  const { error, data } = await fetchGetRequirementModuleTree(currentObjectId.value);

  loading.value = false;

  if (error || !data) {
    moduleTree.value = [];
    return;
  }

  moduleTree.value = data;

  if (data.length > 0 && !selectedModuleId.value) {
    selectedModuleId.value = data[0].id;
    emit('select', data[0].id);
  }
}

function handleNodeSelect(moduleId: string) {
  if (editingNodeId.value || addingChildParentId.value) return;
  selectedModuleId.value = moduleId;
  emit('select', moduleId);
}

function handleStartEdit(module: Api.Product.RequirementModule) {
  editingNodeId.value = module.id;
  editingName.value = module.moduleName;

  nextTick(() => {
    const input = document.querySelector('.module-tree-item.is-editing .el-input__inner') as HTMLInputElement;
    input?.focus();
    input?.select();
  });
}

async function handleEditConfirm(module: Api.Product.RequirementModule) {
  const name = editingName.value.trim();

  editingNodeId.value = undefined;

  if (!name || name === module.moduleName) {
    return;
  }

  await handleUpdateModuleName(module, name);
}

function handleEditCancel() {
  editingNodeId.value = undefined;
}

async function handleUpdateModuleName(module: Api.Product.RequirementModule, name: string) {
  if (!currentObjectId.value) return;

  const { error } = await fetchUpdateRequirementModule({
    id: module.id,
    productId: currentObjectId.value,
    parentId: module.parentId,
    moduleName: name,
    remark: module.remark,
    icon: module.icon,
    sort: module.sort
  });

  if (error) return;

  window.$message?.success('模块名称更新成功');
  await loadModuleTree();
  emit('refresh');
}

function handleStartAddChild(module: Api.Product.RequirementModule) {
  if (addingChildParentId.value) return;

  addingChildParentId.value = module.id;
  newChildModuleName.value = '';

  nextTick(() => {
    const input = document.querySelector('.new-child-module-input input') as HTMLInputElement;
    input?.focus();
  });
}

async function handleAddChildConfirm() {
  const name = newChildModuleName.value.trim();

  const parentId = addingChildParentId.value;
  addingChildParentId.value = undefined;
  newChildModuleName.value = '';

  if (!name) {
    return;
  }

  if (!currentObjectId.value) {
    return;
  }

  if (!parentId) {
    return;
  }

  const { error } = await fetchCreateRequirementModule({
    id: undefined,
    productId: currentObjectId.value,
    parentId,
    moduleName: name,
    remark: null,
    icon: null,
    sort: 0
  });

  if (error) {
    return;
  }

  window.$message?.success('子模块新增成功');
  await loadModuleTree();
  emit('refresh');
}

function handleAddChildCancel() {
  addingChildParentId.value = undefined;
  newChildModuleName.value = '';
}

async function handleDeleteModule(module: Api.Product.RequirementModule) {
  if (!currentObjectId.value) return;

  try {
    await ElMessageBox.confirm(
      `确定要删除模块 "${module.moduleName}" 吗？该模块下的所有需求将被一并删除。`,
      '删除确认',
      {
        confirmButtonText: '确认删除',
        cancelButtonText: '取消',
        type: 'warning'
      }
    );
  } catch {
    return;
  }

  const { error } = await fetchDeleteRequirementModule({
    id: module.id,
    productId: currentObjectId.value
  });

  if (error) return;

  window.$message?.success('模块删除成功');

  if (selectedModuleId.value === module.id) {
    const rootId = rootModule.value?.id || '';
    selectedModuleId.value = rootId;
    emit('select', rootId);
  }

  await loadModuleTree();
  emit('refresh');
}

watch(
  () => currentObjectId.value,
  async id => {
    if (id) {
      selectedModuleId.value = '';
      await loadModuleTree();
    } else {
      moduleTree.value = [];
    }
  },
  { immediate: true }
);

defineExpose({
  loadModuleTree,
  selectedModuleId
});
</script>

<template>
  <ElCard class="requirement-module-tree-card card-wrapper">
    <template #header>
      <div class="module-tree-header">
        <span class="module-tree-header__title">模块</span>
      </div>
    </template>

    <div class="module-tree-list">
      <template v-for="data in moduleTree" :key="data.id">
        <ModuleTreeNode
          :module="data"
          :level="0"
          :selected-module-id="selectedModuleId"
          :editing-node-id="editingNodeId"
          :editing-name="editingName"
          :adding-child-parent-id="addingChildParentId"
          :new-child-module-name="newChildModuleName"
          :root-module-id="rootModule?.id"
          :module-requirement-count-map="moduleRequirementCountMap"
          @select="handleNodeSelect"
          @edit="handleStartEdit"
          @edit-confirm="handleEditConfirm"
          @edit-cancel="handleEditCancel"
          @delete="handleDeleteModule"
          @add-child="handleStartAddChild"
          @add-child-confirm="handleAddChildConfirm"
          @add-child-cancel="handleAddChildCancel"
          @update-editing-name="editingName = $event"
          @update-new-child-module-name="newChildModuleName = $event"
        />
      </template>
    </div>
  </ElCard>
</template>

<style scoped>
.requirement-module-tree-card {
  height: 100%;
}

.requirement-module-tree-card :deep(.el-card__header) {
  padding: 12px 16px;
  border-bottom: none;
}

.requirement-module-tree-card :deep(.el-card__body) {
  padding: 0 16px 16px;
  height: calc(100% - 48px);
  overflow: hidden;
}

.module-tree-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.module-tree-header__title {
  color: rgb(15 23 42 / 94%);
  font-size: 16px;
  font-weight: 700;
}

.module-tree-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
  height: 100%;
  overflow-y: auto;
}

.module-tree-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  min-height: 42px;
  padding: 0 14px;
  border: 1px solid rgb(226 232 240 / 92%);
  border-radius: 14px;
  background-color: rgb(248 250 252 / 96%);
  color: rgb(71 85 105 / 94%);
  font-size: 14px;
  cursor: pointer;
  transition:
    border-color 0.2s ease,
    background-color 0.2s ease,
    color 0.2s ease,
    transform 0.2s ease;
}

.module-tree-item:hover {
  transform: translateY(-1px);
  border-color: rgb(148 163 184 / 56%);
}

.module-tree-item--new {
  border-style: dashed;
  border-color: rgb(148 163 184 / 56%);
}

.module-tree-item__icon {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  color: rgb(100 116 139 / 80%);
}

.module-tree-item__content {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.module-tree-item__input {
  width: 100%;
}

.module-tree-item__input :deep(.el-input__inner) {
  height: 28px;
}
</style>
