<script setup lang="ts">
import { type Ref, computed, inject, ref } from 'vue';
import { useAuth } from '@/hooks/business/auth';

defineOptions({ name: 'ProjectRequirementModuleTreeNode' });

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

const props = withDefaults(defineProps<Props>(), {
  level: 0,
  selectedModuleId: undefined,
  editingNodeId: undefined,
  editingName: undefined,
  addingChildParentId: undefined,
  newChildModuleName: undefined,
  rootModuleId: undefined,
  moduleRequirementCountMap: undefined
});

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

const { hasObjectAuth } = useAuth();
const isRootModule = computed(() => props.module.id === props.rootModuleId);

const hasAnyActionPermission = computed(() => {
  if (isRootModule.value) {
    return hasObjectAuth('project:project:requirement:create');
  }
  return (
    hasObjectAuth('project:project:requirement:create') ||
    hasObjectAuth('project:project:requirement:update') ||
    hasObjectAuth('project:project:requirement:delete')
  );
});

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

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(() => Boolean(props.module.children?.length));
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 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">
        <ElTooltip v-if="!isEditing" :content="module.moduleName" placement="top" :show-after="500">
          <span class="module-tree-item__label">{{ module.moduleName }}</span>
        </ElTooltip>
        <ElInput
          v-else
          :model-value="editingName"
          size="small"
          class="module-tree-item__input"
          placeholder="请输入模块名"
          @update:model-value="emit('updateEditingName', $event)"
          @blur="emit('editConfirm', module)"
          @keyup.enter="emit('editConfirm', module)"
          @keyup.esc="emit('editCancel')"
        />
      </div>

      <div v-if="!isEditing && hasAnyActionPermission" class="module-tree-item__actions" @click.stop>
        <ElTooltip v-if="hasObjectAuth('project:project:requirement:create')" content="新增子模块" placement="top">
          <ElButton link type="primary" class="module-tree-item__action-btn" @click="emit('addChild', module)">
            <icon-mdi-plus class="text-14px" />
          </ElButton>
        </ElTooltip>
        <ElTooltip
          v-if="!isRootModule && hasObjectAuth('project:project:requirement:update')"
          content="编辑"
          placement="top"
        >
          <ElButton link type="primary" class="module-tree-item__action-btn" @click="emit('edit', module)">
            <icon-mdi-pencil-outline class="text-14px" />
          </ElButton>
        </ElTooltip>
        <ElPopconfirm
          v-if="!isRootModule && canDeleteModule && hasObjectAuth('project:project:requirement:delete')"
          title="确定删除该模块吗？"
          @confirm="emit('delete', module)"
        >
          <template #reference>
            <span class="inline-flex" @click.stop>
              <ElTooltip content="删除" placement="top">
                <ElButton link type="danger" class="module-tree-item__action-btn">
                  <icon-mdi-delete-outline class="text-14px" />
                </ElButton>
              </ElTooltip>
            </span>
          </template>
        </ElPopconfirm>
      </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="emit('addChildConfirm')"
          @keyup.enter="emit('addChildConfirm')"
          @keyup.esc="emit('addChildCancel')"
        />
      </div>
    </div>
  </div>
</template>

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

.module-tree-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 36px;
  padding: 6px 12px;
  padding-left: 16px;
  border-radius: 8px;
  color: #475569;
  font-size: 14px;
  cursor: pointer;
  transition:
    background-color 0.15s ease,
    color 0.15s ease;
}

.module-tree-item::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 0;
  border-radius: 0 2px 2px 0;
  background-color: transparent;
  transition:
    height 0.15s ease,
    background-color 0.15s ease;
}

.module-tree-item:hover {
  background-color: #f1f5f9;
}

.module-tree-item.is-active {
  background-color: #f0fdfa;
  color: #0d9488;
  font-weight: 500;
}

.module-tree-item.is-active::before {
  height: 60%;
  background-color: #14b8a6;
}

.module-tree-item.is-root {
  font-weight: 600;
  color: #1e293b;
}

.module-tree-item.is-root:hover {
  background-color: #f8fafc;
}

.module-tree-item.is-root.is-active {
  background-color: #f0fdfa;
  color: #0d9488;
}

.module-tree-item--new {
  border: 1px dashed #cbd5e1;
  background-color: #f8fafc;
}

.module-tree-item--new:hover {
  background-color: #f1f5f9;
}

.module-tree-item__toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  cursor: pointer;
  user-select: none;
  transition: transform 0.2s ease;
  color: #94a3b8;
  border-radius: 4px;
}

.module-tree-item__toggle:hover {
  background-color: #e2e8f0;
  color: #64748b;
}

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

.module-tree-item__icon {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  color: #94a3b8;
}

.module-tree-item.is-active .module-tree-item__icon {
  color: #14b8a6;
}

.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: 26px;
}

.module-tree-item__actions {
  display: flex;
  align-items: center;
  flex-shrink: 0;
  opacity: 0;
  transition: opacity 0.15s 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__action-btn {
  padding: 2px;
  min-width: auto;
  height: auto;
  margin-left: 2px;
  line-height: 1;
}

.module-tree-item__action-btn:first-child {
  margin-left: 0;
}
</style>
