<script setup lang="ts">
import { type Ref, computed, inject, ref } from 'vue';

defineOptions({ name: 'ModuleTreeNode' });

interface Props {
  module: Api.Product.RequirementModule;
  level?: number;
  selectedModuleId?: string;
  editingNodeId?: string | undefined;
  editingName?: string;
  addingChildParentId?: string | undefined;
  newChildModuleName?: string;
  rootModuleId?: string;
  moduleRequirementCountMap?: Map<string, number>;
}

const props = withDefaults(defineProps<Props>(), {
  level: 0
});

const emit = defineEmits([
  'select',
  'edit',
  'editConfirm',
  'editCancel',
  'delete',
  'addChild',
  'addChildConfirm',
  'addChildCancel',
  'updateEditingName',
  'updateNewChildModuleName'
]);

const collapsedModuleIds = inject<Ref<Set<string>>>('collapsedModuleIds', ref(new Set()));
const toggleCollapse = inject<(id: string) => void>('toggleCollapse', () => {});

const isRootModule = computed(() => props.module.id === props.rootModuleId);
const isSelected = computed(() => props.selectedModuleId === props.module.id);
const isEditing = computed(() => props.editingNodeId === props.module.id);
const isAddingChild = computed(() => props.addingChildParentId === props.module.id);
const hasChildren = computed(() => props.module.children && props.module.children.length > 0);
const isCollapsed = computed(() =>
  hasChildren.value && props.module.id ? collapsedModuleIds.value.has(props.module.id) : false
);

const hasRequirements = computed(() => {
  const moduleId = props.module.id;
  if (!moduleId || !props.moduleRequirementCountMap) return false;
  return (props.moduleRequirementCountMap.get(moduleId) || 0) > 0;
});

const canDeleteModule = computed(() => !hasChildren.value && !hasRequirements.value);

const indentStyle = computed(() => {
  if (props.level === 0) return {};
  const indent = 24 + (props.level - 1) * 24;
  return {
    width: `calc(100% - ${indent}px)`,
    marginLeft: `${indent}px`
  };
});

function handleClick() {
  if (props.editingNodeId || props.addingChildParentId) return;
  emit('select', props.module.id);
}

function handleStartEdit() {
  emit('edit', props.module);
}

function handleEditConfirm() {
  emit('editConfirm', props.module);
}

function handleEditCancel() {
  emit('editCancel');
}

function handleStartAddChild() {
  emit('addChild', props.module);
}

function handleDelete() {
  emit('delete', props.module);
}

function handleAddChildConfirm() {
  emit('addChildConfirm');
}

function handleAddChildCancel() {
  emit('addChildCancel');
}

function handleToggle() {
  if (props.module.id) {
    toggleCollapse(props.module.id);
  }
}
</script>

<template>
  <div class="module-tree-node">
    <div
      class="module-tree-item"
      :class="{
        'is-root': isRootModule,
        'is-active': isSelected,
        'is-editing': isEditing
      }"
      :style="indentStyle"
      @click="handleClick"
    >
      <div
        class="module-tree-item__toggle"
        :class="{ 'is-expanded': hasChildren && !isCollapsed }"
        @click.stop="handleToggle"
      >
        <icon-ic-round-chevron-right v-if="hasChildren" class="text-14px" />
      </div>
      <div class="module-tree-item__icon">
        <icon-mdi-folder-open v-if="isRootModule" class="text-16px" />
        <icon-mdi-folder-outline v-else class="text-16px" />
      </div>
      <div class="module-tree-item__content">
        <span v-if="!isEditing" class="module-tree-item__label">{{ module.moduleName }}</span>
        <ElInput
          v-else
          :model-value="editingName"
          size="small"
          class="module-tree-item__input"
          placeholder="请输入模块名"
          @update:model-value="emit('updateEditingName', $event)"
          @blur="handleEditConfirm"
          @keyup.enter="handleEditConfirm"
          @keyup.esc="handleEditCancel"
        />
      </div>

      <div v-if="!isEditing" class="module-tree-item__actions" @click.stop>
        <ElDropdown trigger="click">
          <ElButton text size="small" class="module-tree-item__more-btn">
            <icon-mdi-dots-horizontal class="text-14px" />
          </ElButton>
          <template #dropdown>
            <ElDropdownMenu>
              <ElDropdownItem
                v-auth="{ code: 'project:product:create', source: 'object' }"
                @click="handleStartAddChild"
              >
                <div class="flex items-center gap-6px">
                  <icon-ic-round-plus class="text-14px" />
                  <span>新增子模块</span>
                </div>
              </ElDropdownItem>
              <ElDropdownItem
                v-if="!isRootModule"
                v-auth="{ code: 'project:product:update', source: 'object' }"
                @click="handleStartEdit"
              >
                <div class="flex items-center gap-6px">
                  <icon-mdi-pencil-outline class="text-14px" />
                  <span>编辑</span>
                </div>
              </ElDropdownItem>
              <ElDropdownItem
                v-if="!isRootModule && canDeleteModule"
                v-auth="{ code: 'project:product:delete', source: 'object' }"
                divided
                @click="handleDelete"
              >
                <div class="flex items-center gap-6px text-error">
                  <icon-mdi-delete-outline class="text-14px" />
                  <span>删除</span>
                </div>
              </ElDropdownItem>
            </ElDropdownMenu>
          </template>
        </ElDropdown>
      </div>
    </div>

    <template v-if="hasChildren && !isCollapsed">
      <ModuleTreeNode
        v-for="child in module.children"
        :key="child.id"
        :module="child"
        :level="level + 1"
        :selected-module-id="selectedModuleId"
        :editing-node-id="editingNodeId"
        :editing-name="editingName"
        :adding-child-parent-id="addingChildParentId"
        :new-child-module-name="newChildModuleName"
        :root-module-id="rootModuleId"
        :module-requirement-count-map="moduleRequirementCountMap"
        @select="emit('select', $event)"
        @edit="emit('edit', $event)"
        @edit-confirm="emit('editConfirm', $event)"
        @edit-cancel="emit('editCancel')"
        @delete="emit('delete', $event)"
        @add-child="emit('addChild', $event)"
        @add-child-confirm="emit('addChildConfirm')"
        @add-child-cancel="emit('addChildCancel')"
        @update-editing-name="emit('updateEditingName', $event)"
        @update-new-child-module-name="emit('updateNewChildModuleName', $event)"
      />
    </template>

    <div
      v-if="isAddingChild"
      class="module-tree-item module-tree-item--new"
      :style="{
        width: indentStyle.width,
        marginLeft: level === 0 ? '24px' : `calc(24px + ${level * 24}px)`
      }"
    >
      <div class="module-tree-item__icon">
        <icon-mdi-folder-plus-outline class="text-16px" />
      </div>
      <div class="module-tree-item__content">
        <ElInput
          :model-value="newChildModuleName"
          size="small"
          class="new-child-module-input module-tree-item__input"
          placeholder="请输入模块名"
          @update:model-value="emit('updateNewChildModuleName', $event)"
          @blur="handleAddChildConfirm"
          @keyup.enter="handleAddChildConfirm"
          @keyup.esc="handleAddChildCancel"
        />
      </div>
    </div>
  </div>
</template>

<style scoped>
.module-tree-node {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.module-tree-item {
  display: flex;
  align-items: center;
  gap: 10px;
  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.is-active {
  border-color: rgb(13 148 136 / 42%);
  background-color: rgb(240 253 250 / 98%);
  color: rgb(15 118 110 / 96%);
  font-weight: 600;
}

.module-tree-item.is-root:not(.is-active) .module-tree-item__icon {
  color: rgb(13 148 136 / 80%);
}

.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__toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
  cursor: pointer;
  user-select: none;
  transition: transform 0.2s ease;
  color: rgb(148 163 184);
}

.module-tree-item__toggle.is-expanded svg {
  transform: rotate(90deg);
}

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

.module-tree-item__label {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

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

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

.module-tree-item__actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.module-tree-item:hover .module-tree-item__actions {
  opacity: 1;
}

.module-tree-item.is-editing .module-tree-item__actions {
  opacity: 0;
}

.module-tree-item__more-btn {
  padding: 4px;
}
</style>
