<script lang="ts">
// Named export for recursive self-reference
export default { name: "TreeEntry" };
</script>

<script setup lang="ts">
import { computed, ref, watch, onMounted, onUnmounted } from "vue";
import ConfirmDialog from "./ConfirmDialog.vue";

interface DirEntry {
  name: string;
  path: string;
  is_dir: boolean;
  children?: DirEntry[];
}

const props = defineProps<{
  entry: DirEntry;
  depth: number;
  currentFilePath?: string | null;
}>();

const emit = defineEmits<{
  toggleFolder: [path: string];
  openFile: [path: string];
  createFolder: [path: string];
  createFile: [path: string];
  deleteEntry: [path: string];
  renameEntry: [path: string, newName: string];
}>();

const expanded = ref(true);

// Auto-expand when children are loaded for the first time
watch(
  () => props.entry.children,
  (children, oldChildren) => {
    if (children !== undefined && oldChildren === undefined) {
      expanded.value = true;
    }
  },
);

const isActive = computed(() => {
  return props.currentFilePath != null && props.currentFilePath === props.entry.path;
});

// ── File type detection ─────────────────────────────────────
const fileType = computed(() => {
  if (props.entry.is_dir) return "folder";
  const ext = props.entry.name.split(".").pop()?.toLowerCase();
  if (ext === "md") return "markdown";
  if (["png", "jpg", "jpeg", "gif", "webp", "avif", "svg", "bmp", "ico"].includes(ext ?? "")) return "image";
  if (["mp4", "webm", "mov", "m4v", "ogv", "avi", "mkv"].includes(ext ?? "")) return "video";
  return "file";
});

const fileIcon = computed(() => {
  switch (fileType.value) {
    case "markdown": return "ri-markdown-line";
    case "image":     return "ri-image-line";
    case "video":     return "ri-film-line";
    default:          return "ri-file-line";
  }
});

// ── Menu ─────────────────────────────────────────────────
const menuOpen = ref(false);
const menuRef = ref<HTMLElement | null>(null);
const rowRef = ref<HTMLElement | null>(null);
const menuButtonRef = ref<HTMLElement | null>(null);
const menuStyle = ref<Record<string, string>>({});

function toggleMenu(e: MouseEvent) {
  e.stopPropagation();
  if (!menuOpen.value) {
    if (menuButtonRef.value) {
      const btnRect = menuButtonRef.value.getBoundingClientRect();
      const spaceBelow = window.innerHeight - btnRect.bottom;
      const left = Math.min(btnRect.left, window.innerWidth - 150);
      menuStyle.value = spaceBelow >= 140
        ? {
            position: "fixed",
            top: `${btnRect.bottom + 2}px`,
            left: `${left}px`,
          }
        : {
            position: "fixed",
            bottom: `${window.innerHeight - btnRect.top + 2}px`,
            left: `${left}px`,
          };
    }
  }
  menuOpen.value = !menuOpen.value;
}

function closeMenu() {
  menuOpen.value = false;
}

function onDocumentClick(e: MouseEvent) {
  if (menuRef.value && !menuRef.value.contains(e.target as Node)) {
    closeMenu();
  }
}

onMounted(() => {
  document.addEventListener("click", onDocumentClick);
});

onUnmounted(() => {
  document.removeEventListener("click", onDocumentClick);
});

// ── Actions ─────────────────────────────────────────────────
function handleCreateFolder() {
  closeMenu();
  const name = window.prompt("请输入文件夹名称：");
  if (name && name.trim()) {
    emit("createFolder", props.entry.path + "/" + name.trim());
  }
}

function handleCreateFile() {
  closeMenu();
  const name = window.prompt("请输入文件名称（无需 .md 后缀）：");
  if (name && name.trim()) {
    emit("createFile", props.entry.path + "/" + name.trim() + ".md");
  }
}

function handleRename() {
  closeMenu();
  const newName = window.prompt("请输入新名称：", props.entry.name);
  if (newName && newName.trim() && newName.trim() !== props.entry.name) {
    emit("renameEntry", props.entry.path, newName.trim());
  }
}

// ── Delete confirmation ─────────────────────────────────────
const confirmShow = ref(false);
const confirmTitle = ref("");
const confirmMessage = ref("");

function handleDelete() {
  closeMenu();
  confirmTitle.value = props.entry.is_dir ? "删除文件夹" : "删除文件";
  confirmMessage.value = props.entry.is_dir
    ? `确定要永久删除文件夹「${props.entry.name}」及其所有内容吗？此操作不可撤销。`
    : `确定要永久删除文件「${props.entry.name}」吗？此操作不可撤销。`;
  confirmShow.value = true;
}

function onConfirmDelete() {
  confirmShow.value = false;
  emit("deleteEntry", props.entry.path);
}

// ── Tree click ──────────────────────────────────────────────
function onClick() {
  if (props.entry.is_dir) {
    if (props.entry.children === undefined) {
      emit("toggleFolder", props.entry.path);
    } else {
      expanded.value = !expanded.value;
    }
  } else {
    emit("openFile", props.entry.path);
  }
}
</script>

<template>
  <!-- ── Confirm dialog ── -->
  <ConfirmDialog
    :show="confirmShow"
    :title="confirmTitle"
    :message="confirmMessage"
    confirm-text="删除"
    cancel-text="取消"
    :danger="true"
    @confirm="onConfirmDelete"
    @cancel="confirmShow = false"
  />

  <template v-if="entry.is_dir">
    <!-- Folder row -->
    <div
      ref="rowRef"
      class="tree-folder flex items-center gap-1 px-2 py-1 rounded-md text-sm cursor-pointer select-none relative group"
      :style="{ paddingLeft: `${depth * 16 + 8}px` }"
      @click="onClick"
    >
      <i
        class="tree-arrow ri-arrow-right-s-line text-sm transition-transform shrink-0"
        :class="expanded && entry.children ? 'rotate-90' : ''"
      ></i>
      <i class="tree-entry-icon ri-folder-2-line text-base shrink-0"></i>
      <span class="truncate flex-1 min-w-0">{{ entry.name }}</span>

      <!-- More button -->
      <button
        ref="menuButtonRef"
        class="tree-more-btn shrink-0 ml-auto opacity-0 group-hover:opacity-100 transition-opacity"
        type="button"
        title="更多操作"
        @click.stop="toggleMenu"
      >
        <i class="ri-more-line"></i>
      </button>

      <!-- Dropdown menu -->
      <Teleport to="body">
        <div
          v-if="menuOpen"
          ref="menuRef"
          class="tree-dropdown"
          :style="menuStyle"
          @click.stop
        >
          <button class="tree-dropdown-item" @click="handleCreateFolder">
            <i class="ri-folder-add-line"></i>
            <span>新建文件夹</span>
          </button>
          <button class="tree-dropdown-item" @click="handleCreateFile">
            <i class="ri-file-add-line"></i>
            <span>新建 MD 文件</span>
          </button>
          <button class="tree-dropdown-item" @click="handleRename">
            <i class="ri-edit-line"></i>
            <span>重命名</span>
          </button>
          <div class="tree-dropdown-sep"></div>
          <button class="tree-dropdown-item tree-dropdown-item-danger" @click="handleDelete">
            <i class="ri-delete-bin-line"></i>
            <span>删除文件夹</span>
          </button>
        </div>
      </Teleport>
    </div>

    <!-- Children (recursive) -->
    <template v-if="expanded && entry.children">
      <TreeEntry
        v-for="child in entry.children"
        :key="child.path"
        :entry="child"
        :depth="depth + 1"
        :currentFilePath="currentFilePath"
        @toggle-folder="(path: string) => emit('toggleFolder', path)"
        @open-file="(path: string) => emit('openFile', path)"
        @create-folder="(path: string) => emit('createFolder', path)"
        @create-file="(path: string) => emit('createFile', path)"
        @delete-entry="(path: string) => emit('deleteEntry', path)"
        @rename-entry="(path: string, name: string) => emit('renameEntry', path, name)"
      />
    </template>
  </template>

  <!-- File -->
  <div
    v-else
    ref="rowRef"
    :class="[
      'tree-file flex items-center gap-1.5 px-2 py-1 rounded-md text-sm cursor-pointer transition-colors relative group',
      isActive
        ? 'tree-file-active font-medium'
        : 'tree-file-idle',
    ]"
    :style="{ paddingLeft: `${depth * 16 + 8}px` }"
    @click="onClick"
  >
    <i :class="['tree-entry-icon', fileIcon, 'text-sm shrink-0']"></i>
    <span class="truncate flex-1 min-w-0">{{ entry.name }}</span>

    <!-- More button -->
    <button
      ref="menuButtonRef"
      class="tree-more-btn shrink-0 ml-auto opacity-0 group-hover:opacity-100 transition-opacity"
      type="button"
      title="更多操作"
      @click.stop="toggleMenu"
    >
      <i class="ri-more-line"></i>
    </button>

    <!-- Dropdown menu -->
    <Teleport to="body">
      <div
        v-if="menuOpen"
        ref="menuRef"
        class="tree-dropdown"
        :style="menuStyle"
        @click.stop
      >
        <button class="tree-dropdown-item" @click="handleRename">
          <i class="ri-edit-line"></i>
          <span>重命名</span>
        </button>
        <div class="tree-dropdown-sep"></div>
        <button class="tree-dropdown-item tree-dropdown-item-danger" @click="handleDelete">
          <i class="ri-delete-bin-line"></i>
          <span>删除</span>
        </button>
      </div>
    </Teleport>
  </div>
</template>

<style scoped>
.tree-folder {
  color: var(--app-text-soft);
}

.tree-folder:hover {
  background: var(--app-hover);
}

.tree-arrow {
  color: var(--app-subtle);
}

.tree-entry-icon {
  color: color-mix(in srgb, var(--app-accent) 68%, transparent);
}

.tree-file-idle {
  color: var(--app-muted);
}

.tree-file-idle:hover {
  background: var(--app-hover);
  color: var(--app-text);
}

.tree-file-active {
  background: var(--app-hover);
  color: var(--app-accent);
}

/* ── More button ────────────────────────────── */
.tree-more-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 4px;
  background: transparent;
  color: var(--app-muted);
  font-size: 14px;
  cursor: pointer;
  transition:
    background-color 0.12s ease,
    color 0.12s ease;
  flex-shrink: 0;
}

.tree-more-btn:hover {
  background: var(--app-border);
  color: var(--app-text);
}

/* ── Dropdown ───────────────────────────────── */
.tree-dropdown {
  position: fixed;
  z-index: 9999;
  background: var(--app-surface);
  border: 1px solid var(--app-border-strong);
  border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  min-width: 140px;
  padding: 4px;
}

.tree-dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 13px;
  color: var(--app-text);
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  white-space: nowrap;
}

.tree-dropdown-item:hover {
  background-color: var(--app-hover);
}

.tree-dropdown-item i {
  font-size: 15px;
  color: var(--app-muted);
  flex-shrink: 0;
}

.tree-dropdown-item-danger {
  color: #e53e3e;
}

.tree-dropdown-item-danger i {
  color: #e53e3e;
}

.tree-dropdown-item-danger:hover {
  background-color: #fff5f5;
}

.tree-dropdown-sep {
  height: 1px;
  margin: 4px 6px;
  background: var(--app-border);
}
</style>
