<template>
  <div class="task-sidebar">
    <div class="sidebar-header">
      <span class="sidebar-title">
        <Icon icon="ant-design:menu-outlined" class="mr-1" />
        任务
      </span>
    </div>

    <div class="sidebar-nav">
      <div
        v-for="item in NAV_ITEMS"
        :key="item.id"
        class="sidebar-item"
        :class="{ active: currentView === item.id }"
        @click="emit('view-select', item.id)"
      >
        <Icon :icon="item.icon" class="sidebar-item-icon" />
        <span>{{ item.label }}</span>
      </div>
    </div>

    <div class="sidebar-divider"></div>

    <div class="sidebar-section">
      <div class="sidebar-quick-header" @click="quickAccessExpanded = !quickAccessExpanded">
        <Icon icon="tasklist-arrow-down|svg" class="quick-access-arrow" :class="{ expanded: quickAccessExpanded }" />
        <span class="sidebar-quick-title">快速访问</span>
      </div>
      <template v-if="quickAccessExpanded">
        <div
          v-for="item in QUICK_ACCESS_ITEMS"
          :key="item.id"
          class="sidebar-item sidebar-quick-access-sub"
          :class="{ active: currentView === item.id }"
          @click="onQuickAccessClick(item)"
        >
          <Icon :icon="item.icon" class="sidebar-item-icon" />
          <span>{{ item.label }}</span>
        </div>
      </template>
    </div>

    <div class="sidebar-divider"></div>

    <div class="sidebar-section sidebar-lists-section">
      <div class="sidebar-favorites-header">
        <Icon icon="tasklist-task-list|svg" class="sidebar-favorites-icon" />
        <span class="sidebar-favorites-name">收藏清单</span>
        <a-dropdown :trigger="['click']">
          <Icon icon="ant-design:plus-outlined" class="sidebar-group-add" @click.stop />
          <template #overlay>
            <a-menu @click="onAddMenuClick">
              <a-menu-item key="new-list">
                <Icon icon="ant-design:file-add-outlined" class="mr-1" />
                新建清单
              </a-menu-item>
              <a-menu-item key="new-group">
                <Icon icon="ant-design:folder-add-outlined" class="mr-1" />
                新建分组
              </a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>
      </div>
      <div class="sidebar-favorites-items">
        <draggable :list="localUngroupedTaskLists" group="tasklists" item-key="id" handle=".list-drag-handle" :animation="200" @end="onDragEnd">
          <template #item="{ element: taskList }">
            <div
              v-if="renamingId !== taskList.id"
              class="sidebar-item"
              :class="{ active: currentListId === taskList.id }"
              :data-list-id="taskList.id"
              @click="emit('list-select', taskList.id)"
              @mouseenter="hoveredListId = taskList.id"
              @mouseleave="hoveredListId = ''"
            >
              <span class="list-drag-handle">
                <Icon icon="tasklist-list-drag-handle|svg" />
              </span>
              <Icon icon="ant-design:file-text-outlined" class="sidebar-item-icon" />
              <span class="sidebar-item-name">{{ taskList.name }}</span>
              <a-dropdown :trigger="['click']">
                <Icon v-show="hoveredListId === taskList.id" icon="ant-design:ellipsis-outlined" class="sidebar-item-more" @click.stop />
                <template #overlay>
                  <a-menu @click="onListMenuClick($event, taskList.id, taskList.name)">
                    <a-menu-item v-if="canEditList(taskList.id)" key="rename">
                      <Icon icon="ant-design:edit-outlined" class="mr-1" />
                      重命名
                    </a-menu-item>
                    <a-menu-item key="remove">
                      <Icon icon="ant-design:minus-circle-outlined" class="mr-1" />
                      移除
                    </a-menu-item>
                  </a-menu>
                </template>
              </a-dropdown>
            </div>
            <div v-else class="sidebar-item sidebar-item-renaming">
              <span class="list-drag-handle-placeholder"></span>
              <Icon icon="ant-design:file-text-outlined" class="sidebar-item-icon" style="opacity: 0.4" />
              <a-input ref="renameInputRef" v-model:value="renameValue" size="small" style="flex: 1" @press-enter="confirmInlineRename" @blur="confirmInlineRename" />
            </div>
          </template>
        </draggable>
      </div>

      <draggable :list="localUserGroups" group="tasklistgroups" item-key="id" :animation="200" drag-class="group-drag-ghost" @start="onGroupDragStart" @end="onGroupDragEnd">
        <template #item="{ element: group }">
          <div :data-group-id="group.id" :class="{ 'group-being-dragged': draggingGroupId === group.id }">
            <div
              v-if="group.delFlag !== 1 && renamingId !== group.id"
              class="sidebar-group-header"
              @mousedown="onGroupMouseDown($event, group.id)"
              @mousemove="onGroupMouseMove($event)"
              @mouseup="onGroupMouseUp($event, group.id)"
            >
          <Icon icon="tasklist-arrow-down|svg" class="group-collapse-arrow" :class="{ collapsed: collapsedGroups[group.id] || draggingGroupId === group.id }" />
          <span class="sidebar-group-name">{{ group.name }}</span>
          <a-dropdown :trigger="['click']" @click.stop>
            <Icon icon="ant-design:ellipsis-outlined" class="sidebar-group-more" @click.stop />
            <template #overlay>
              <a-menu @click="onGroupMenuClick($event, group.id, group.name)">
                <a-menu-item key="rename">
                  <Icon icon="ant-design:edit-outlined" class="mr-1" />
                  重命名
                </a-menu-item>
                <a-menu-item key="delete" danger>
                  <Icon icon="ant-design:delete-outlined" class="mr-1" />
                  删除
                </a-menu-item>
              </a-menu>
            </template>
          </a-dropdown>
          <Icon icon="ant-design:plus-outlined" class="sidebar-group-add" @click.stop="startNewList(group.id)" />
        </div>
        <div v-if="group.delFlag !== 1 && renamingId === group.id" class="sidebar-group-header sidebar-group-renaming" @click.stop>
          <Icon icon="tasklist-arrow-down|svg" class="group-collapse-arrow" :class="{ collapsed: collapsedGroups[group.id] || draggingGroupId === group.id }" />
          <a-input ref="renameInputRef" v-model:value="renameValue" size="small" style="flex: 1" @press-enter="confirmInlineRename" @blur="confirmInlineRename" />
        </div>
        <template v-if="group.delFlag !== 1 && !collapsedGroups[group.id]">
          <div class="sidebar-group-items" :data-group-id="group.id">
            <draggable
              :list="getLocalGroupTaskLists(group)"
              group="tasklists"
              item-key="id"
              handle=".list-drag-handle"
              :animation="200"
              @end="onDragEnd"
            >
              <template #item="{ element: taskList }">
                <div
                  v-if="renamingId !== taskList.id"
                  class="sidebar-item"
                  :class="{ active: currentListId === taskList.id }"
                  :data-list-id="taskList.id"
                  @click="emit('list-select', taskList.id)"
                  @mouseenter="hoveredListId = taskList.id"
                  @mouseleave="hoveredListId = ''"
                >
                  <span class="list-drag-handle">
                    <Icon icon="tasklist-list-drag-handle|svg" />
                  </span>
                  <Icon icon="ant-design:file-text-outlined" class="sidebar-item-icon" />
                  <span class="sidebar-item-name">{{ taskList.name }}</span>
                  <a-dropdown :trigger="['click']">
                    <Icon v-show="hoveredListId === taskList.id" icon="ant-design:ellipsis-outlined" class="sidebar-item-more" @click.stop />
                    <template #overlay>
                      <a-menu @click="onListMenuClick($event, taskList.id, taskList.name)">
                        <a-menu-item v-if="canEditList(taskList.id)" key="rename">
                          <Icon icon="ant-design:edit-outlined" class="mr-1" />
                          重命名
                        </a-menu-item>
                        <a-menu-item key="remove">
                          <Icon icon="ant-design:minus-circle-outlined" class="mr-1" />
                          移除
                        </a-menu-item>
                      </a-menu>
                    </template>
                  </a-dropdown>
                </div>
                <div v-else class="sidebar-item sidebar-item-renaming">
                  <span class="list-drag-handle-placeholder"></span>
                  <Icon icon="ant-design:file-text-outlined" class="sidebar-item-icon" style="opacity: 0.4" />
                  <a-input ref="renameInputRef" v-model:value="renameValue" size="small" style="flex: 1" @press-enter="confirmInlineRename" @blur="confirmInlineRename" />
                </div>
              </template>
            </draggable>
            <div
              v-if="getLocalGroupTaskLists(group).length === 0"
              class="sidebar-empty-hint"
            >
              可拖拽清单加入该分组
            </div>
          </div>
        </template>
      </div>
    </template>
  </draggable>

      <div v-if="showNewGroupInput" class="sidebar-new-group-row">
        <Icon icon="ant-design:plus-outlined" class="sidebar-new-icon" />
        <a-input
          v-model:value="newGroupName"
          size="small"
          placeholder="输入分组名称..."
          autofocus
          style="flex: 1"
          @press-enter="submitNewGroup"
          @blur="showNewGroupInput = false"
        />
      </div>
      <div v-else class="sidebar-new-group-btn" @click="showNewGroupInput = true">
        <Icon icon="ant-design:plus-outlined" class="sidebar-new-icon" />
        <span>新建分组</span>
      </div>
    </div>
  </div>
</template>

<script lang="ts" setup>
  import { ref, computed, watch, nextTick } from 'vue';
  import Icon from '/@/components/Icon/index';
  import draggable from 'vuedraggable';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { NAV_ITEMS, QUICK_ACCESS_ITEMS, QUICK_ACCESS_TAB_MAP } from '../types';
  import type { TaskListGroup, ViewType } from '../types';

  const { createConfirm } = useMessage();

  const props = defineProps<{
    taskListGroups: TaskListGroup[];
    currentView: ViewType;
    currentListId: string;
    favoriteIdMap: Map<string, string>;
    permissionMap: Map<string, string>;
  }>();

  const emit = defineEmits<{
    'view-select': [view: ViewType];
    'list-select': [listId: string];
    'create-list-modal': [groupId: string];
    'create-group': [name: string];
    'rename-list': [listId: string, newName: string];
    'delete-list': [listId: string];
    'remove-favorite': [listId: string];
    'rename-group': [groupId: string, newName: string];
    'delete-group': [groupId: string];
    'quick-access-tab-click': [tabKey: string];
    'move-list': [favoriteId: string, targetGroupId: string, sortOrder: number];
    'move-group': [groupId: string, targetSortOrder: number];
  }>();

  function onQuickAccessClick(item: { id: string }) {
    const tabKey = QUICK_ACCESS_TAB_MAP[item.id];
    if (tabKey) {
      emit('quick-access-tab-click', tabKey);
    }
  }

  const quickAccessExpanded = ref(true);

  const ungroupedTaskLists = computed(() => {
    const group = props.taskListGroups.find((g) => g.id === '__ungrouped__');
    if (group) {
      return [...group.taskLists].filter((l) => l.delFlag !== 1).sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
    }
    return [];
  });

  const userGroups = computed(() => {
    return props.taskListGroups.filter((g) => g.id !== '__ungrouped__' && g.delFlag !== 1).sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
  });

  // 本地可变副本，供 draggable :list 模式直接修改，实现乐观更新
  const localUngroupedTaskLists = ref<any[]>([]);
  const localUserGroups = ref<any[]>([]);
  const localGroupTaskListsMap = ref<Record<string, any[]>>({});

  watch(ungroupedTaskLists, (val) => {
    localUngroupedTaskLists.value = [...val];
  }, { immediate: true });

  watch(userGroups, (val) => {
    localUserGroups.value = val.map((g) => ({
      ...g,
      taskLists: [...(g.taskLists || [])],
    }));
    // 同步分组内清单到 map
    const newMap: Record<string, any[]> = {};
    for (const g of val) {
      newMap[g.id] = [...(g.taskLists || [])].filter((l) => l.delFlag !== 1).sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
    }
    localGroupTaskListsMap.value = newMap;
  }, { immediate: true });

  function getGroupTaskLists(group: any) {
    return [...group.taskLists].filter((l) => l.delFlag !== 1).sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0));
  }

  function getLocalGroupTaskLists(group: any) {
    if (localGroupTaskListsMap.value[group.id]) {
      return localGroupTaskListsMap.value[group.id];
    }
    // 兜底：如果没有本地缓存，从原始数据计算
    const list = getGroupTaskLists(group);
    localGroupTaskListsMap.value[group.id] = list;
    return list;
  }

  const hoveredListId = ref('');
  const collapsedGroups = ref<Record<string, boolean>>({});
  const showNewGroupInput = ref(false);
  const newGroupName = ref('');
  const renamingId = ref('');
  const renamingType = ref<'list' | 'group'>('list');
  const renameValue = ref('');
  const renameInputRef = ref<HTMLInputElement | null>(null);

  watch(renamingId, async (val) => {
    if (val) {
      await nextTick();
      renameInputRef.value?.focus();
    }
  });

  const draggingGroupId = ref('');
  const dragStartX = ref(0);
  const dragStartY = ref(0);
  const isDragging = ref(false);
  const DRAG_THRESHOLD = 5;

  function toggleGroup(groupId: string) {
    collapsedGroups.value = {
      ...collapsedGroups.value,
      [groupId]: !collapsedGroups.value[groupId],
    };
  }

  function onDragEnd(evt: any) {
    const itemEl = evt.item;
    const listId = itemEl?.dataset?.listId;
    if (!listId) return;

    const favoriteId = props.favoriteIdMap.get(listId);
    if (!favoriteId) return;

    const toContainer = evt.to;
    const targetGroupId = toContainer?.closest('[data-group-id]')?.dataset?.groupId || '';

    const newIndex = evt.newIndex ?? 0;

    emit('move-list', favoriteId, targetGroupId, newIndex + 1);
  }

  function onGroupMouseDown(evt: MouseEvent, groupId: string) {
    dragStartX.value = evt.clientX;
    dragStartY.value = evt.clientY;
    isDragging.value = false;
  }

  function onGroupMouseMove(evt: MouseEvent) {
    const dx = Math.abs(evt.clientX - dragStartX.value);
    const dy = Math.abs(evt.clientY - dragStartY.value);
    
    if (dx > DRAG_THRESHOLD || dy > DRAG_THRESHOLD) {
      isDragging.value = true;
    }
  }

  function onGroupMouseUp(evt: MouseEvent, groupId: string) {
    if (!isDragging.value) {
      toggleGroup(groupId);
    }
    isDragging.value = false;
    dragStartX.value = 0;
    dragStartY.value = 0;
  }

  function onGroupDragStart(evt: any) {
    const itemEl = evt.item;
    const groupId = itemEl?.dataset?.groupId;
    if (groupId) {
      draggingGroupId.value = groupId;
    }
  }

  function onGroupDragEnd(evt: any) {
    draggingGroupId.value = '';
    isDragging.value = false;
    const itemEl = evt.item;
    const groupId = itemEl?.dataset?.groupId || itemEl?.closest('[data-group-id]')?.dataset?.groupId;
    if (!groupId) return;
    // 拖拽结束后保持分组折叠状态，防止展开跳动
    collapsedGroups.value[groupId] = true;
    const newIndex = evt.newIndex ?? 0;
    emit('move-group', groupId, newIndex + 1);
  }

  function canEditList(listId: string): boolean {
    const perm = props.permissionMap.get(listId);
    return perm === '1' || perm === '2';
  }

  function onAddMenuClick({ key }: { key: string }) {
    if (key === 'new-list') {
      startNewList('');
    } else if (key === 'new-group') {
      showNewGroupInput.value = true;
      newGroupName.value = '';
    }
  }

  function startNewList(groupId: string) {
    emit('create-list-modal', groupId);
  }

  function onListMenuClick({ key }: { key: string }, listId: string, currentName: string) {
    if (key === 'rename') {
      renamingId.value = listId;
      renamingType.value = 'list';
      renameValue.value = currentName;
    } else if (key === 'remove') {
      createConfirm({
        iconType: 'warning',
        title: '确认移除',
        content: '确定从收藏清单中移除吗？',
        okText: '确认',
        cancelText: '取消',
        onOk: () => {
          emit('remove-favorite', listId);
        },
      });
    }
  }

  function onGroupMenuClick({ key }: { key: string }, groupId: string, currentName: string) {
    if (key === 'rename') {
      renamingId.value = groupId;
      renamingType.value = 'group';
      renameValue.value = currentName;
    } else if (key === 'delete') {
      emit('delete-group', groupId);
    }
  }

  function confirmInlineRename() {
    const name = renameValue.value.trim();
    if (name && renamingId.value) {
      if (renamingType.value === 'list') {
        emit('rename-list', renamingId.value, name);
      } else {
        emit('rename-group', renamingId.value, name);
      }
    }
    renamingId.value = '';
    renameValue.value = '';
  }

  function submitNewGroup() {
    if (newGroupName.value.trim()) {
      emit('create-group', newGroupName.value.trim());
      newGroupName.value = '';
      showNewGroupInput.value = false;
    }
  }
</script>

<style lang="less" scoped>
  .task-sidebar {
    width: 240px;
    min-width: 240px;
    height: 100%;
    background: #fff;
    border-right: 1px solid #f0f0f0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    user-select: none;
  }

  .sidebar-header {
    padding: 14px 16px 10px;
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .sidebar-title {
    font-size: 16px;
    font-weight: 600;
    color: #1f1f1f;
    display: flex;
    align-items: center;
  }

  .sidebar-nav {
    padding: 4px 8px;
  }

  .sidebar-divider {
    height: 1px;
    background: #f0f0f0;
    margin: 4px 12px;
  }

  .sidebar-section {
    padding: 4px 8px;
  }

  .sidebar-quick-header {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    cursor: pointer;
    color: #8c8c8c;
    font-size: 14px;
    user-select: none;

    &:hover {
      color: #595959;
    }
  }

  .sidebar-quick-title {
    font-size: 14px;
    font-weight: 600;
    color: #595959;
  }

  .quick-access-arrow {
    font-size: 12px;
    color: #8c8c8c;
    transition: transform 0.2s ease;
    transform: rotate(-90deg);

    &.expanded {
      transform: rotate(0deg);
    }
  }

  .sidebar-item.sidebar-quick-access-sub {
    padding-left: 30px;
    font-size: 14px;
  }

  .sidebar-section-header {
    padding: 6px 8px 2px;
  }

  .sidebar-section-title {
    font-size: 14px;
    font-weight: 600;
    color: #8c8c8c;
    text-transform: uppercase;
    letter-spacing: 0.5px;
  }

  .sidebar-lists-section {
    flex: 1;
    overflow-y: auto;
    padding-bottom: 0;
  }

  .sidebar-favorites-header {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 8px 2px;
    position: relative;
  }

  .sidebar-favorites-icon {
    color: #8f959e;
    flex-shrink: 0;
    font-size: 14px;
  }

  .sidebar-favorites-name {
    font-size: 14px;
    font-weight: 600;
    color: #595959;
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .sidebar-favorites-items {
    .sidebar-item {
      padding-left: 8px;
    }
  }

  .sidebar-group-items {
    .sidebar-item {
      padding-left: 8px;
    }
  }

  .sidebar-group-header {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 6px 8px 2px;
    cursor: pointer;
    position: relative;

    &:hover .sidebar-group-name {
      color: #333;
    }

    .sidebar-group-more,
    .sidebar-group-add {
      opacity: 0;
      transition: opacity 0.15s;
    }

    &:hover .sidebar-group-more,
    &:hover .sidebar-group-add {
      opacity: 1;
    }
  }

  .group-collapse-arrow {
    font-size: 12px;
    color: #8f959e;
    transition: transform 0.2s ease;
    flex-shrink: 0;
    width: 16px;
    text-align: center;

    &.collapsed {
      transform: rotate(-90deg);
    }
  }

  .sidebar-group-name {
    font-size: 14px;
    font-weight: 600;
    color: #595959;
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .sidebar-group-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    font-size: 10px;
    color: #999;
  }

  .sidebar-group-add {
    margin-left: auto;
    font-size: 14px;
    color: #999;
    cursor: pointer;
    padding: 2px 4px;
    border-radius: 4px;
    &:hover {
      color: #1677ff;
      background: #e6f4ff;
    }
  }

  .sidebar-group-more {
    font-size: 16px;
    color: #999;
    padding: 2px;
    border-radius: 4px;
    flex-shrink: 0;
    &:hover {
      color: #1677ff;
      background: #e6f4ff;
    }
  }

  .sidebar-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    cursor: pointer;
    border-radius: 6px;
    margin: 1px 0;
    font-size: 14px;
    color: #595959;
    transition: all 0.15s ease;
    position: relative;

    &:hover {
      background: #f5f5f5;
      color: #333;
    }

    &.active {
      background: #e6f4ff;
      color: #1677ff;
      font-weight: 500;
    }
  }

  .sidebar-item-icon {
    font-size: 14px;
    flex-shrink: 0;
  }

  .sidebar-item-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
  }

  .sidebar-item-more {
    font-size: 14px;
    color: #999;
    padding: 2px;
    border-radius: 4px;
    flex-shrink: 0;
    &:hover {
      color: #1677ff;
      background: #e6f4ff;
    }
  }

  .list-drag-handle {
    cursor: grab;
    font-size: 12px;
    color: transparent;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    transition: color 0.15s;
    &:active {
      cursor: grabbing;
    }
  }

  .sidebar-item:hover .list-drag-handle {
    color: #c0c4cc;
    &:hover {
      color: #8c8c8c;
    }
  }

  .list-drag-handle-placeholder {
    width: 14px;
    flex-shrink: 0;
  }

  .sidebar-empty-hint {
    padding: 8px 10px 4px 38px;
    font-size: 12px;
    color: #bfbfbf;
    font-style: italic;
  }

  .sidebar-new-group-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    margin: 4px 0;
    cursor: pointer;
    border-radius: 6px;
    font-size: 14px;
    color: #8c8c8c;
    &:hover {
      background: #f5f5f5;
      color: #333;
    }
  }

  .sidebar-new-group-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 10px;
    margin: 4px 0;
  }

  .sidebar-new-item-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px 4px 8px;
    margin: 2px 0;
  }

  .group-being-dragged > .sidebar-group-items {
    display: none !important;
  }

  .group-drag-ghost {
    opacity: 0.6;
  }

  .sidebar-item-renaming {
    background: #f5f6f7;
  }

  .sidebar-group-renaming {
    background: #f5f6f7;
  }

  .sidebar-new-icon {
    font-size: 12px;
    color: #8c8c8c;
  }
</style>
