<template>
  <el-container class="home-page" :class="{'is-mobile': isMobile}">
    <!-- Sidebar -->
    <SidebarMenu
        :is-collapsed="isCollapsed"
        :is-mobile="isMobile"
        :active-menu="activeMenu"
        :category-tree="categoryTree"
        @toggle-collapse="isCollapsed = !isCollapsed"
        @show-create-group="showCreateGroupDialog = true"
        @select-file="handleSelectFile"
        @show-rename-dialog="openRenameDialog"
        @group-deleted="handleGroupDeleted"
        @show-system-settings="showSystemSettingsDialog = true"
        @show-update-password="showUpdatePasswordDialog = true"
        @logout="handleLogout"
    />

    <!-- Main Content -->
    <el-container>
      <el-main class="content">
        <!-- Note Editor View -->
        <NoteEditor
            v-if="showEditor"
            :edit-data="editData"
            @back="handleEditorBack"
            @update:edit-data="handleSaveSuccess"
        />

        <!-- Note Preview View -->
        <NotePreview
            v-else-if="selectedFile"
            :file="selectedFile"
            :is-mobile="isMobile"
            :is-user-logged-in="userStore.isLoggedIn"
            :has-more-chunks="hasMoreChunks"
            :user-role="userStore.userInfo?.role || 'USER'"
            @back="selectedFile = null"
            @edit="editNote(selectedFile)"
            @delete="deleteNote(selectedFile)"
            @open-rename-dialog="openRenameDialog"
            @show-move-note-dialog="showMoveNoteDialog = true"
            @show-privacy-dialog="showPrivacyDialog = true"
            @export="handleExport"
        />

        <!-- Home/List View -->
        <div v-else class="list-view-container">
          <HomeHeader
              :is-mobile="isMobile"
              v-model:search-keyword="searchKeyword"
              @search="handleSearch"
              @reset-view="resetToHomeView"
              @logout="handleLogout"
              @show-update-password="showUpdatePasswordDialog = true"
              @show-system-settings="showSystemSettingsDialog = true"
              @show-create-note="showCreateNoteDialog = true"
              @upload-markdown="handleMarkdownUpload"
              @toggle-collapse="isCollapsed = !isCollapsed"
          />
          <div class="note-list-wrapper" ref="noteListWrapper" @scroll="handleScroll">
            <NoteList
                :files="displayedFiles"
                :is-user-logged-in="userStore.isLoggedIn"
                @preview="previewFile"
            />
            <div v-if="isLoadingMore" class="loading-more">
              <el-icon class="is-loading"><Loading /></el-icon>
              <span>加载中...</span>
            </div>
            <div v-else-if="hasMoreFiles && !showEditor && !selectedFile" class="load-more-hint">
              <span>继续滚动加载更多...</span>
            </div>
            <div v-else-if="!hasMoreFiles && displayedFiles.length > 0" class="no-more-hint">
              <span>没有更多笔记了</span>
            </div>
          </div>
        </div>
      </el-main>
    </el-container>

    <!-- Sidebar Overlay for Mobile -->
    <div v-if="isMobile && !isCollapsed" class="sidebar-overlay" @click="isCollapsed = true"></div>

    <!-- Mobile FAB for creating note -->
    <el-button
        v-if="isMobile && userStore.isLoggedIn && !showEditor && !selectedFile"
        class="fab"
        type="primary"
        circle
        @click="showCreateNoteDialog = true"
    >
      <el-icon><Plus /></el-icon>
    </el-button>

    <!-- Dialogs -->
    <CreateGroupDialog
        v-model:visible="showCreateGroupDialog"
        :category-options="categoryTree"
        @group-created="fetchGroupings"
    />
    <CreateNoteDialog
        v-model:visible="showCreateNoteDialog"
        :category-options="categoryTree"
        @create-note="handleCreateNote"
    />
    <RenameDialog
        v-model:visible="showRenameDialog"
        :item="itemToRename"
        @renamed="handleRenamed"
    />
    <SelectGroupDialog
        v-model:visible="showSelectGroupDialog"
        :category-options="categoryTree"
        :file-to-import="fileToImport"
        @import-success="handleImportSuccess"
    />
    <MoveNoteDialog
        v-model:visible="showMoveNoteDialog"
        :category-options="categoryTree"
        :note-to-move="selectedFile"
        @move-success="handleMoveSuccess"
    />
    <SystemSettingsDialog v-model:visible="showSystemSettingsDialog" />
    <UpdatePasswordDialog
        v-model:visible="showUpdatePasswordDialog"
        @password-updated="handleLogout"
    />
    <PrivacyDialog
        v-model:visible="showPrivacyDialog"
        :note="selectedFile"
        @privacy-changed="handlePrivacyChanged"
    />
  </el-container>
</template>

<script setup>
import { onMounted, ref, nextTick, watch, computed, onBeforeUnmount, watchEffect, provide } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import Vditor from 'vditor';
import 'vditor/dist/index.css';
import { escapeHtml } from '@/utils/security';
import DOMPurify from 'dompurify';
import {
  groupingAll,
  markdownList,
  Preview,
  PreviewChunk,
  updateMarkdown,
  searchMarkdown,
  deleteMarkdown,
  getRecentFiles,
  validateToken,
} from '@/api/CommonApi.js';
import { useUserStore } from '../stores/user';
import { useRouter } from 'vue-router';
import { privateNoteContent } from '../utils/privateNoteContent.js';
import jsPDF from 'jspdf';
import html2canvas from 'html2canvas';

// Import Components
import SidebarMenu from './home/SidebarMenu.vue';
import HomeHeader from './home/HomeHeader.vue';
import NoteList from './home/NoteList.vue';
import NotePreview from './home/NotePreview.vue';
import NoteEditor from './home/NoteEditor.vue';
import CreateGroupDialog from './home/dialogs/CreateGroupDialog.vue';
import CreateNoteDialog from './home/dialogs/CreateNoteDialog.vue';
import RenameDialog from './home/dialogs/RenameDialog.vue';
import SelectGroupDialog from './home/dialogs/SelectGroupDialog.vue';
import MoveNoteDialog from './home/dialogs/MoveNoteDialog.vue';
import SystemSettingsDialog from './home/dialogs/SystemSettingsDialog.vue';
import UpdatePasswordDialog from './home/dialogs/UpdatePasswordDialog.vue';
import PrivacyDialog from './home/dialogs/PrivacyDialog.vue';
import { Plus, Loading } from "@element-plus/icons-vue";

// Basic Setup
const userStore = useUserStore();
const router = useRouter();

// State
const searchKeyword = ref('');
const categoryTree = ref([]);
const groupMarkdownFiles = ref([]);
const displayedFiles = ref([]);
const currentPage = ref(0);
const pageSize = ref(16);
const isLoadingMore = ref(false);
const loadCount = ref(0); // 记录加载次数，用于动态增加加载数量
const noteListWrapper = ref(null);
const showEditor = ref(false);
const selectedFile = ref(null);
const editData = ref(null);
const activeMenu = ref('all');
const isCollapsed = ref(window.innerWidth < 768);
const isMobile = ref(window.innerWidth < 768);

// Dialog visibility
const showCreateGroupDialog = ref(false);
const showCreateNoteDialog = ref(false);
const showRenameDialog = ref(false);
const showSelectGroupDialog = ref(false);
const showMoveNoteDialog = ref(false);
const showSystemSettingsDialog = ref(false);
const showUpdatePasswordDialog = ref(false);
const showPrivacyDialog = ref(false);

// Vditor 渲染引擎就绪状态
const vditorReady = ref(false);
// 提供给子组件使用
provide('vditorReady', vditorReady);

// 大文件分块加载状态
const currentChunkIndex = ref(0);
const hasMoreChunks = ref(false);
const isLoadingChunk = ref(false);
const totalChunks = ref(0);

// Data for dialogs
const itemToRename = ref(null);
const fileToImport = ref(null);

const hasMoreFiles = computed(() => {
  return displayedFiles.value.length < groupMarkdownFiles.value.length;
});

const resetEdit = () => {
  editData.value = null;
};

// --- Core Logic ---

// Data Fetching
const fetchGroupings = async () => {
  try {
    const allCategories = await groupingAll("");
    categoryTree.value = buildTree(allCategories || []);
  } catch (error) {
    categoryTree.value = [];
  }
};

const buildTree = (items) => {
  const tree = [];
  const itemMap = new Map();
  items.forEach(item => {
    itemMap.set(String(item.id), { ...item, children: [] });
  });
  itemMap.forEach(item => {
    const parentId = String(item.parentId);
    if (parentId !== '0' && itemMap.has(parentId)) {
      itemMap.get(parentId).children.push(item);
    } else {
      tree.push(item);
    }
  });
  const cleanTree = (nodes) => {
    nodes.forEach(node => {
      if (node.children.length === 0) delete node.children;
      else cleanTree(node.children);
    });
  };
  cleanTree(tree);
  return tree;
};

const resetToHomeView = async () => {
  resetEdit();
  selectedFile.value = null;
  showEditor.value = false;
  searchKeyword.value = '';
  activeMenu.value = 'all';
  currentPage.value = 0;
  loadCount.value = 0; // 重置加载计数
  try {
    groupMarkdownFiles.value = await getRecentFiles(100) || [];
    updateDisplayedFiles();
  } catch (error) {
    // 错误已在 axios 拦截器中显示，这里不再重复显示
    console.error('获取最近文件失败:', error);
    groupMarkdownFiles.value = [];
    displayedFiles.value = [];
  }
};

// 计算动态加载数量：基础16个，每次增加8个，最多48个
const getDynamicPageSize = () => {
  const baseSize = 16;
  const increment = 8;
  const maxSize = 48;
  return Math.min(baseSize + loadCount.value * increment, maxSize);
};

const updateDisplayedFiles = () => {
  const start = 0;
  const dynamicPageSize = getDynamicPageSize();
  // 计算实际显示数量：首次16个，之后动态增加
  const end = displayedFiles.value.length === 0 
    ? dynamicPageSize 
    : displayedFiles.value.length + dynamicPageSize;
  displayedFiles.value = groupMarkdownFiles.value.slice(start, end);
};

const loadMoreFiles = () => {
  if (isLoadingMore.value || !hasMoreFiles.value) return;
  isLoadingMore.value = true;
  
  setTimeout(() => {
    loadCount.value++;
    currentPage.value++;
    updateDisplayedFiles();
    isLoadingMore.value = false;
  }, 300);
};

const handleScroll = (e) => {
  const { scrollTop, scrollHeight, clientHeight } = e.target;
  // 距离底部 200px 时自动加载，给用户更流畅的体验
  if (scrollHeight - scrollTop - clientHeight < 200 && hasMoreFiles.value && !isLoadingMore.value) {
    loadMoreFiles();
  }
};

// 预览区域滚动处理（用于大文件分块加载）
const handlePreviewScroll = (e) => {
  const { scrollTop, scrollHeight, clientHeight } = e.target;
  // 距离底部 300px 时加载下一页内容
  if (scrollHeight - scrollTop - clientHeight < 300 && hasMoreChunks.value && !isLoadingChunk.value) {
    loadMoreContent();
  }
};

// Event Handlers from Components
const handleSelectFile = async (data) => {
  resetEdit();
  try {
    const files = await markdownList(data.id);
    groupMarkdownFiles.value = files || [];
    currentPage.value = 0;
    loadCount.value = 0; // 重置加载计数
    updateDisplayedFiles();
    selectedFile.value = null;
    showEditor.value = false;
    activeMenu.value = `group-${data.id}`;
  } catch (error) {
    // 错误已在 axios 拦截器中显示，这里不再重复显示
    console.error('获取笔记列表失败:', error);
    groupMarkdownFiles.value = [];
    displayedFiles.value = [];
  }
};

const handleGroupDeleted = async () => {
  await fetchGroupings();
  await resetToHomeView();
};

const handleCreateNote = (payload) => {
  resetEdit();
  // 直接设置编辑数据，ID将在第一次保存时由后端生成
  editData.value = payload;
  showEditor.value = true;
  selectedFile.value = null; // Ensure preview is hidden
};

const handleEditorBack = async (data) => {
  showEditor.value = false;
  if (data && data.id) {
    // 重置渲染缓存
    lastRenderedKey = null;
    currentChunkIndex.value = 0;
    hasMoreChunks.value = false;
    isLoadingChunk.value = false;
    totalChunks.value = 0;

    // 设置预览状态并加载内容
    selectedFile.value = {
      ...data,
      groupingName: data.groupingName || getCategoryName(data.groupingId),
      isLoading: true,
      isRendering: false
    };

    // 加载笔记内容
    await loadNoteChunk(data.id, 0);
  } else {
    selectedFile.value = null;
    resetToHomeView();
  }
};

const getCategoryName = (groupId) => {
  if (!groupId) return '';
  const findName = (items) => {
    for (const item of items) {
      if (item.id === groupId) return item.grouping;
      if (item.children) {
        const name = findName(item.children);
        if (name) return name;
      }
    }
    return null;
  };
  return findName(categoryTree.value) || '';
};

const handleSaveSuccess = (updatedFile) => {
  selectedFile.value = updatedFile;

  const index = groupMarkdownFiles.value.findIndex(f => f.id === updatedFile.id);
  if (index !== -1) {
    groupMarkdownFiles.value[index] = updatedFile;
  } else {
    groupMarkdownFiles.value.unshift(updatedFile);
  }
  
  updateDisplayedFiles();
  fetchGroupings();
};

const previewFile = async (file) => {
  resetEdit();
  if (!file || file.id === null) {
    editData.value = file;
    selectedFile.value = null;
    return;
  }
  // 重置渲染缓存，确保每次打开笔记都重新渲染
  lastRenderedKey = null;
  // 重置分块加载状态
  currentChunkIndex.value = 0;
  hasMoreChunks.value = false;
  isLoadingChunk.value = false;
  totalChunks.value = 0;
  
  // 先立即显示预览页（加载状态），让用户感知到响应
  selectedFile.value = { ...file, content: '', isLoading: true, isRendering: false };
  showEditor.value = false;

  // 异步加载内容（使用分块加载）
  await loadNoteChunk(file.id, 0);
};

// 分块加载笔记内容
const loadNoteChunk = async (fileId, chunkIndex) => {
  if (isLoadingChunk.value) return;
  
  isLoadingChunk.value = true;
  try {
    const chunkData = await PreviewChunk(fileId, chunkIndex, 10000);
    
    if (selectedFile.value && selectedFile.value.id === fileId) {
      // 更新分块加载状态
      currentChunkIndex.value = chunkData.chunkIndex;
      hasMoreChunks.value = chunkData.hasMore;
      totalChunks.value = chunkData.totalChunks;
      
      // 如果是第一块，直接设置内容；否则追加内容
      let newContent;
      if (chunkIndex === 0) {
        newContent = chunkData.chunk;
      } else {
        newContent = selectedFile.value.content + chunkData.chunk;
      }
      
      // 如果 Vditor 渲染引擎未就绪，显示渲染中状态
      const isRendering = !vditorReady.value;
      
      selectedFile.value = { 
        ...selectedFile.value, 
        content: newContent, 
        isLoading: false, 
        isRendering,
        title: chunkData.title || selectedFile.value.title,
        isPrivate: chunkData.isPrivate !== undefined ? chunkData.isPrivate : selectedFile.value.isPrivate
      };
    }
  } catch (error) {
    // 错误已在 axios 拦截器中显示，这里不再重复显示
    console.error('获取笔记内容失败:', error);
    selectedFile.value = null;
  } finally {
    isLoadingChunk.value = false;
  }
};

// 加载更多内容（滚动到底部时调用）
const loadMoreContent = async () => {
  if (!selectedFile.value || !hasMoreChunks.value || isLoadingChunk.value) return;
  
  const nextChunkIndex = currentChunkIndex.value + 1;
  await loadNoteChunk(selectedFile.value.id, nextChunkIndex);
};

const editNote = (file) => {
  editData.value = { ...file };
  showEditor.value = true;
  isCollapsed.value = true; // Collapse sidebar on mobile when editing
};

const deleteNote = (file) => {
  ElMessageBox.confirm(`确定要删除笔记 “${file.title}” 吗？`, '警告', {
    confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning',
  }).then(async () => {
    try {
      await deleteMarkdown(file.id);
      ElMessage.success('笔记已删除');
      selectedFile.value = null;
      await fetchGroupings();
      await resetToHomeView();
    } catch (error) {
      // 错误已在 axios 拦截器中显示，这里不再重复显示
      console.error('删除笔记失败:', error);
    }
  });
};

const openRenameDialog = (item, type) => {
  itemToRename.value = { ...item, type };
  showRenameDialog.value = true;
};

const handleRenamed = async (newName) => {
  await fetchGroupings();
  if (selectedFile.value && itemToRename.value.type === 'file' && selectedFile.value.id === itemToRename.value.id) {
    // 直接更新当前选中文件的标题
    selectedFile.value.title = newName;
    // 更新笔记列表中的对应项
    const index = groupMarkdownFiles.value.findIndex(f => f.id === selectedFile.value.id);
    if (index !== -1) {
      groupMarkdownFiles.value[index].title = newName;
    }
    // 重新获取文件内容以确保是最新的
    previewFile(selectedFile.value); // Refresh preview
  } else {
    resetToHomeView();
  }
};

const handleMarkdownUpload = (file) => {
  fileToImport.value = file;
  showSelectGroupDialog.value = true;
};

const handleImportSuccess = async () => {
  await fetchGroupings();
  await resetToHomeView();
};

const handleMoveSuccess = async () => {
  selectedFile.value = null;
  await fetchGroupings();
  await resetToHomeView();
};

const handlePrivacyChanged = (updatedFile) => {
  selectedFile.value = updatedFile;
  const index = groupMarkdownFiles.value.findIndex(f => f.id === updatedFile.id);
  if (index !== -1) {
    groupMarkdownFiles.value[index] = updatedFile;
  }
};

const handleSearch = async () => {
  if (!searchKeyword.value.trim()) {
    await resetToHomeView();
    return;
  }
  try {
    groupMarkdownFiles.value = await searchMarkdown(searchKeyword.value) || [];
    currentPage.value = 0;
    loadCount.value = 0; // 重置加载计数
    updateDisplayedFiles();
    selectedFile.value = null;
    showEditor.value = false;
    activeMenu.value = 'search';
  } catch (error) {
    // 错误已在 axios 拦截器中显示，这里不再重复显示
    console.error('搜索失败:', error);
  }
};

const handleLogout = () => {
  userStore.logout();
  ElMessage.success('已退出登录');
  router.push('/login');
};

// Export Logic
const handleExport = async (format) => {
  if (!selectedFile.value) return;
  try {
    await validateToken();
  } catch {
    ElMessage.error('登录已过期，请重新登录');
    handleLogout();
    return;
  }

  const title = (selectedFile.value.title || '未命名笔记').replace(/[<>:"/\\|?*]/g, '_');
  const content = selectedFile.value.content;
  const previewElement = document.querySelector('.markdown-preview');

  if (!previewElement) {
    ElMessage.error('无法找到预览区域');
    return;
  }

  ElMessage.info(`正在导出为 ${format.toUpperCase()}...`);

  try {
    if (format === 'md') {
      const blob = new Blob([content], { type: 'text/markdown;charset=utf-8' });
      downloadBlob(blob, `${title}.md`);
    } else if (format === 'html') {
        // 修复：对title进行HTML转义，使用DOMPurify清理内容防止XSS
        const escapedTitle = escapeHtml(title);
        const sanitizedContent = DOMPurify.sanitize(previewElement.innerHTML, {
          ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'code', 'pre', 'ul', 'ol', 'li', 'blockquote', 'img', 'br', 'hr', 'table', 'thead', 'tbody', 'tr', 'th', 'td'],
          ALLOWED_ATTR: ['href', 'title', 'class', 'src', 'alt', 'width', 'height']
        });
        const fullHtml = `<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><title>${escapedTitle}</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css"><style>body{box-sizing:border-box;min-width:200px;max-width:980px;margin:0 auto;padding:45px;}</style></head><body class="markdown-body"><h1>${escapedTitle}</h1>${sanitizedContent}</body></html>`;
        const blob = new Blob([fullHtml], { type: 'text/html;charset=utf-8' });
        downloadBlob(blob, `${escapedTitle}.html`);
    } else if (format === 'pdf') {
        const canvas = await html2canvas(previewElement, { scale: 2, useCORS: true });
        const pdf = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
        const pageHeight = pdf.internal.pageSize.getHeight() - 20;
        const pageWidth = pdf.internal.pageSize.getWidth() - 20;
        const imgHeight = (canvas.height * pageWidth) / canvas.width;
        let heightLeft = imgHeight;
        let position = 10;
        const imgData = canvas.toDataURL('image/png');
        pdf.addImage(imgData, 'PNG', 10, position, pageWidth, imgHeight);
        heightLeft -= pageHeight;
        while (heightLeft > 0) {
            position = -pageHeight * (pdf.internal.getNumberOfPages()) + 10;
            pdf.addPage();
            pdf.addImage(imgData, 'PNG', 10, position, pageWidth, imgHeight);
            heightLeft -= pageHeight;
        }
        pdf.save(`${title}.pdf`);
    }
    ElMessage.success(`${format.toUpperCase()} 导出成功`);
  } catch (error) {
    // 错误已在 axios 拦截器中显示，这里不再重复显示
    console.error('导出失败:', error);
  }
};

const downloadBlob = (blob, filename) => {
  const url = URL.createObjectURL(blob);
  const link = document.createElement('a');
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
};


// Lifecycle and Watchers
onMounted(async () => {
  await fetchGroupings();
  await resetToHomeView();
  window.addEventListener('resize', handleResize);
  
  // 预加载 Vditor 渲染引擎（lute.min.js），避免第一次点击笔记时等待下载
  preloadVditor();
});

// 预加载 Vditor 渲染引擎
const preloadVditor = () => {
  // 创建一个隐藏的容器用于预加载
  const preloadContainer = document.createElement('div');
  preloadContainer.style.cssText = 'position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden;';
  document.body.appendChild(preloadContainer);
  
  // 调用 Vditor.preview 会触发 lute.min.js 的下载
  Vditor.preview(preloadContainer, '# 预加载', {
    mode: 'light',
    after: () => {
      // 渲染引擎加载完成
      vditorReady.value = true;
      // 清理预加载容器
      if (preloadContainer.parentNode) {
        preloadContainer.parentNode.removeChild(preloadContainer);
      }
      console.log('Vditor 渲染引擎已就绪');
    }
  });
};

onBeforeUnmount(() => {
  window.removeEventListener('resize', handleResize);
});

const handleResize = () => {
  isMobile.value = window.innerWidth < 768;
  if (isMobile.value) {
    isCollapsed.value = true;
  }
};

// Vditor 渲染优化
let lastRenderedKey = null;

// 处理 Markdown 内容中的图片 URL，将相对路径转换为完整路径
const processImageUrls = (content) => {
  if (!content) return '';
  const baseUrl = import.meta.env.VITE_API_BASE_URL || '';
  if (!baseUrl) return content;
  
  // 匹配 Markdown 图片语法 ![alt](/api/images/preview/xxx.png)
  return content.replace(
    /!\[([^\]]*)\]\((\/api\/images\/preview\/[^)]+)\)/g,
    (_match, alt, relativeUrl) => {
      // 确保 URL 格式正确
      const fullUrl = baseUrl.endsWith('/') && relativeUrl.startsWith('/')
        ? baseUrl + relativeUrl.substring(1)
        : baseUrl + relativeUrl;
      return `![${alt}](${fullUrl})`;
    }
  );
};

// 渲染 Markdown 内容的函数
const renderMarkdown = async (file) => {
  if (!file || showEditor.value) return;
  
  // 使用文件ID+内容长度作为渲染标识，内容变化时重新渲染
  const renderKey = `${file.id}-${file.content?.length || 0}`;
  if (lastRenderedKey === renderKey) return;
  
  // 如果正在加载中，等待加载完成再渲染
  if (file.isLoading) {
    return;
  }
  
  // 等待 DOM 更新完成
  await nextTick();
  
  // 使用 requestAnimationFrame 确保浏览器已完成布局和绘制
  requestAnimationFrame(() => {
    const previewElement = document.querySelector('.markdown-preview');
    if (previewElement) {
      let contentToRender = (file.isPrivate === 1 && !userStore.isLoggedIn) ? privateNoteContent : file.content;
      // 处理图片 URL
      contentToRender = processImageUrls(contentToRender);
      // 先清空内容，避免闪烁
      previewElement.innerHTML = '';
      Vditor.preview(previewElement, contentToRender || '', {
        mode: 'light',
        hljs: { enable: true, style: 'github' },
        after: () => {
          // 渲染完成后，如果文件有 isRendering 标记，移除它
          if (selectedFile.value && selectedFile.value.isRendering) {
            selectedFile.value = { ...selectedFile.value, isRendering: false };
          }
          // 为图片添加懒加载属性
          const images = previewElement.querySelectorAll('img');
          images.forEach(img => {
            if (!img.hasAttribute('loading')) {
              img.setAttribute('loading', 'lazy');
            }
          });
          // 添加滚动监听，用于大文件分块加载
          if (hasMoreChunks.value) {
            previewElement.addEventListener('scroll', handlePreviewScroll);
          }
        }
      });
      lastRenderedKey = renderKey;
    } else {
      // 如果元素不存在，100ms 后重试
      setTimeout(() => renderMarkdown(file), 100);
    }
  });
};

// 监听选中文件变化，自动渲染
watch(() => selectedFile.value, (newFile) => {
  if (newFile && !showEditor.value) {
    renderMarkdown(newFile);
  } else if (!newFile) {
    // 用户返回列表页，重置渲染缓存
    lastRenderedKey = null;
  }
}, { deep: true, immediate: true });

// 监听编辑器状态变化
watch(showEditor, (isEditor) => {
  if (!isEditor && selectedFile.value) {
    renderMarkdown(selectedFile.value);
  }
});

</script>

<style>
/* Global styles can remain if they are truly global */
.hide-popper {
  display: none !important;
}
.markdown-preview .vditor-reset pre {
  max-height: none !important;
  overflow: visible !important;
}
.markdown-preview .vditor-reset pre code {
  max-height: none !important;
  overflow-y: visible !important;
  word-break: break-all !important;
  white-space: pre-wrap !important;
  display: block;
}
</style>

<style scoped>
.list-view-container {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.note-list-wrapper {
  flex: 1;
  overflow-y: auto;
}

.home-page {
  height: 100vh;
  overflow: hidden;
  background: var(--bg-gradient);
  background-attachment: fixed;
}

.content {
  padding: 1.5rem;
  background-color: transparent;
  height: 100vh;
  overflow-y: auto;
}

.sidebar-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  z-index: 1000;
}

.fab {
  position: fixed;
  bottom: 80px;
  right: 20px;
  z-index: 100;
  width: 56px;
  height: 56px;
  box-shadow: 0 4px 12px rgba(0,0,0,.15);
}

.loading-more {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  gap: 8px;
  color: var(--text-color-secondary);
}

.load-more-trigger {
  display: flex;
  justify-content: center;
  padding: 20px;
}

/* 没有更多笔记了 - 美化样式 */
.no-more-hint {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 30px 20px;
  margin: 10px 0;
}

.no-more-hint span {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 24px;
  background: linear-gradient(135deg, #f5f7fa 0%, #e4e7ed 100%);
  border-radius: 24px;
  color: #909399;
  font-size: 14px;
  font-weight: 500;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
  border: 1px solid #ebeef5;
}

.no-more-hint span::before {
  content: '';
  display: inline-block;
  width: 4px;
  height: 4px;
  background-color: #c0c4cc;
  border-radius: 50%;
}

.no-more-hint span::after {
  content: '';
  display: inline-block;
  width: 4px;
  height: 4px;
  background-color: #c0c4cc;
  border-radius: 50%;
}

/* 暗黑模式适配 */
.dark-theme .no-more-hint span {
  background: linear-gradient(135deg, #2c2c3d 0%, #1e1e2f 100%);
  color: #606266;
  border-color: #2c2c3d;
}

.dark-theme .no-more-hint span::before,
.dark-theme .no-more-hint span::after {
  background-color: #606266;
}

/* 继续滚动加载更多提示 */
.load-more-hint {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20px;
  color: var(--el-color-primary);
  font-size: 14px;
  font-weight: 500;
}
</style>