// background.js - 后台服务

// 安装或更新时初始化
chrome.runtime.onInstalled.addListener(async (details) => {
  console.log('MiniMark 已安装/更新');

  // 初始化默认配置
  const config = await chrome.storage.local.get(['autoSync', 'syncInterval']);
  if (config.syncInterval === undefined) {
    await chrome.storage.local.set({
      autoSync: false,
      syncInterval: 1440, // 默认每天同步一次(分钟)
      lastSyncTime: null,
      syncStatus: null
    });
  }

  // 如果启用了自动同步,设置定时任务
  if (config.autoSync) {
    setupAutoSync(config.syncInterval || 1440);
  }
  // 仅在首次安装时标记为未同步,避免更新扩展后误清"已同步"状态
  if (details.reason === 'install') {
    try { await markUnsynced(); } catch(e) { console.warn('初始化标记未同步失败:', e); }
  }
});

// 在后台监听本地书签变化,实时标记为未同步并更新角标
chrome.bookmarks.onCreated.addListener(() => { markUnsynced().catch(e=>console.warn(e)); });
chrome.bookmarks.onRemoved.addListener(() => { markUnsynced().catch(e=>console.warn(e)); });
chrome.bookmarks.onChanged.addListener(() => { markUnsynced().catch(e=>console.warn(e)); });
chrome.bookmarks.onMoved.addListener(() => { markUnsynced().catch(e=>console.warn(e)); });

// 启动时同步角标状态
chrome.runtime.onStartup.addListener(() => {
  updateActionBadge().catch(e=>console.warn(e));
  cleanupOnStartup().catch(e=>console.warn(e));
});

// 标记为未同步(对比 lastSyncCount 判断)
async function markUnsynced() {
  try {
    const res = await chrome.storage.local.get(['lastSyncCount']);
    const tree = await chrome.bookmarks.getTree();
    const current = countBookmarks(tree[0]);
    const last = res.lastSyncCount !== undefined ? res.lastSyncCount : null;
    // 如果没有 lastSyncCount(首次)且 current>0,视为未同步
    const hasUnsynced = (last === null && current > 0) || (last !== null && current !== last);
    await chrome.storage.local.set({ hasUnsynced });
    await updateActionBadge();
  } catch (e) {
    console.warn('标记未同步失败:', e);
  }
}

// 根据 storage 中的 hasUnsynced 更新扩展图标角标(红点)
async function updateActionBadge() {
  try {
    const res = await chrome.storage.local.get(['hasUnsynced', 'githubToken', 'giteeToken']);
    const has = !!res.hasUnsynced;
    const loggedIn = !!(res.githubToken || res.giteeToken);

    // 如果未登录任何平台,则不显示角标(即使本地有未同步标记)
    if (!loggedIn) {
      chrome.action.setBadgeText({ text: '' });
      return;
    }

    if (has) {
      // 使用一个小圆点作为角标文本并设置为红色
      chrome.action.setBadgeText({ text: '●' });
      try { chrome.action.setBadgeBackgroundColor({ color: '#FF3B30' }); } catch(e) { /* ignore */ }
    } else {
      chrome.action.setBadgeText({ text: '' });
    }
  } catch (e) {
    console.warn('更新角标失败:', e);
  }
}

// 当相关 storage 变更时自动刷新角标(例如 token 变更、hasUnsynced 变更)
chrome.storage.onChanged.addListener((changes, areaName) => {
  if (areaName !== 'local') return;
  const keys = Object.keys(changes);
  const watched = ['hasUnsynced', 'githubToken', 'giteeToken', 'lastSyncCount'];
  if (keys.some(k => watched.includes(k))) {
    updateActionBadge().catch(e => console.warn('storage change 更新角标失败:', e));
  }
});

// 监听来自popup的消息
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action === 'syncNow' || request.action === 'uploadToRemote') {
    // 上传到远程
    performSync(request.platform)
      .then(result => sendResponse({ success: true, gistId: result.gistId, count: result.count }))
      .catch(error => sendResponse({ success: false, error: error.message }));
    return true; // 保持消息通道开启
  } else if (request.action === 'downloadFromRemote') {
    // 从远程下载
    restoreFromRemote(request.platform)
      .then(result => sendResponse({ success: true, count: result.count }))
      .catch(error => sendResponse({ success: false, error: error.message }));
    return true;
  } else if (request.action === 'getRemoteBookmarkCount') {
    // 获取远程书签数量
    getRemoteBookmarkCount(request.platform)
      .then(count => sendResponse({ success: true, count }))
      .catch(error => sendResponse({ success: false, error: error.message }));
    return true;
  } else if (request.action === 'verifyToken') {
    verifyToken(request.platform)
      .then((user) => sendResponse({ success: true, user }))
      .catch((error) => sendResponse({ success: false, error: error.message }));
    return true;
  } else if (request.action === 'findExistingGist') {
    // 查找已存在的 Gist
    findExistingGist(request.platform)
      .then(result => sendResponse({ success: true, gistId: result.gistId, count: result.count }))
      .catch(error => sendResponse({ success: false, error: error.message }));
    return true;
  } else if (request.action === 'analyzeSyncStatus') {
    analyzeSyncStatus(request.platform)
      .then(analysis => sendResponse({ success: true, analysis }))
      .catch(error => sendResponse({ success: false, error: error.message || String(error) }));
    return true;
  } else if (request.action === 'cleanupOldGists') {
    // 清理同名旧 Gist(可指定平台或全部)
    const platforms = request.platform === 'all'
      ? ['github', 'gitee']
      : [request.platform || 'all'];
    const tasks = [];
    if (platforms.includes('github') || platforms.includes('all')) tasks.push(cleanupOldGists('github'));
    if (platforms.includes('gitee') || platforms.includes('all')) tasks.push(cleanupOldGists('gitee'));
    Promise.all(tasks)
      .then(() => sendResponse({ success: true }))
      .catch(error => sendResponse({ success: false, error: error.message }));
    return true;
  } else if (request.action === 'updateAutoSync') {
    // 更新自动同步设置
    if (request.enabled) {
      chrome.storage.local.get(['syncInterval'], (result) => {
        setupAutoSync(result.syncInterval || 1440);
      });
    } else {
      chrome.alarms.clear('autoSync');
    }
    sendResponse({ success: true });
  } else if (request.action === 'clearLocalBookmarks' || request.action === 'clearAllBookmarks') {
    clearLocalBookmarks()
      .then(() => sendResponse({ success: true }))
      .catch(error => sendResponse({ success: false, error: error.message }));
    return true;
  }
});

// 监听定时任务
chrome.alarms.onAlarm.addListener((alarm) => {
  if (alarm.name === 'autoSync') {
    console.log('执行自动同步...');
    performAutoSync().catch(error => {
      console.error('自动同步失败:', error);
    });
  }
});

// 设置自动同步定时任务
function setupAutoSync(intervalMinutes) {
  chrome.alarms.create('autoSync', {
    periodInMinutes: intervalMinutes
  });
  console.log(`自动同步已设置,间隔: ${intervalMinutes} 分钟`);
}

// 智能自动同步:比较本地和远程数量,选择合适的同步方向
async function performAutoSync() {
  try {
    const config = await chrome.storage.local.get([
      'githubToken',
      'giteeToken',
      'githubGistId',
      'giteeGistId',
      'syncMode'
    ]);

    // 获取本地书签数量
    const bookmarks = await chrome.bookmarks.getTree();
    const localCount = countBookmarks(bookmarks[0]);

    // 对每个已配置的平台执行智能同步
    const platforms = [];
    if (config.githubToken) platforms.push('github');
    if (config.giteeToken) platforms.push('gitee');

    for (const platform of platforms) {
      try {
        const gistId = platform === 'github' ? config.githubGistId : config.giteeGistId;
        const syncMode = config.syncMode;

        // 合并模式:直接走 performSync,其内部会先把远端并入本地再上传(双向合并)
        if (syncMode === 'merge') {
          console.log(`${platform}: 合并模式 - 双向合并`);
          await performSync(platform);
          continue;
        }

        if (!gistId) {
          // 如果没有远程备份,直接上传
          console.log(`${platform}: 没有远程备份,执行上传`);
          await performSync(platform);
          continue;
        }

        // 获取远程书签数量
        const remoteCount = await getRemoteBookmarkCount(platform);
        console.log(`${platform}: 本地 ${localCount} 个,远程 ${remoteCount} 个`);

        // 智能决策(覆盖模式):
        // 1. 如果远程数量 > 本地数量:从远程下载(避免覆盖更多的数据)
        // 2. 如果本地数量 >= 远程数量:上传到远程
        if (remoteCount > localCount) {
          console.log(`${platform}: 远程书签更多,从远程同步到本地`);
          await restoreFromRemote(platform);
        } else {
          console.log(`${platform}: 本地书签更多或相等,上传到远程`);
          await performSync(platform);
        }
      } catch (error) {
        console.error(`${platform} 自动同步失败:`, error);
        // 继续处理下一个平台
      }
    }

    console.log('自动同步完成');
  } catch (error) {
    console.error('自动同步失败:', error);
    throw error;
  }
}

// 执行同步
async function performSync(platform) {
  try {
    // 获取配置
    const config = await chrome.storage.local.get([
      'githubToken',
      'giteeToken',
      'githubGistId',
      'giteeGistId'
    ]);

    if (!platform) {
      throw new Error('未指定同步平台');
    }

    const token = platform === 'github' ? config.githubToken : config.giteeToken;
    const gistId = platform === 'github' ? config.githubGistId : config.giteeGistId;

    if (!token) {
      throw new Error(`未配置 ${platform === 'github' ? 'GitHub' : 'Gitee'} Token`);
    }

    // 没有本地记录的 Gist ID 时,先尝试查找已存在的同名 Gist,避免重复创建
    if (!gistId) {
      try {
        const existing = await findExistingGist(platform);
        if (existing && existing.gistId) {
          gistId = existing.gistId;
          if (platform === 'github') config.githubGistId = gistId;
          else config.giteeGistId = gistId;
          console.log(`${platform}: 复用已存在的 Gist ${gistId},不再新建`);
        }
      } catch (e) {
        console.warn(`查找已存在 ${platform} Gist 失败,将继续创建新 Gist:`, e);
      }
    }

    // 没有本地记录的 Gist ID 时,先尝试查找已存在的同名 Gist,避免重复创建
    if (!gistId) {
      try {
        const existing = await findExistingGist(platform);
        if (existing && existing.gistId) {
          gistId = existing.gistId;
          if (platform === 'github') config.githubGistId = gistId;
          else config.giteeGistId = gistId;
          console.log(`${platform}: 复用已存在的 Gist ${gistId},不再新建`);
        }
      } catch (e) {
        console.warn(`查找已存在 ${platform} Gist 失败,将继续创建新 Gist:`, e);
      }
    }

    // 合并模式:先将远端备份合并进本地,再做上传(保证两端新增都保留)
    const syncMode = (await chrome.storage.local.get(['syncMode'])).syncMode;
    if (syncMode === 'merge') {
      try {
        const remote = await fetchRemoteBookmarkData(platform);
        if (remote && remote.bookmarks) {
          await mergeRemoteIntoLocal(remote.bookmarks);
          console.log('合并模式:已把远端书签合并进本地');
        }
      } catch (e) {
        console.warn('合并远端到本地失败(继续以本地为准上传):', e);
      }
    }

    // 获取所有书签
    const bookmarks = await chrome.bookmarks.getTree();
    const bookmarkCount = countBookmarks(bookmarks[0]);

    // 直接使用原始书签树(保留标题中的 emoji,Gitee Gist 内容本身支持 emoji)
    const cleanedBookmarks = bookmarks;

    const bookmarkData = {
      version: '1.0',
      timestamp: Date.now(),
      count: bookmarkCount,
      bookmarks: cleanedBookmarks
    };

    // 检查数据大小
    const dataSize = JSON.stringify(bookmarkData).length;
    const dataSizeMB = (dataSize / 1024 / 1024).toFixed(2);
    console.log(`书签数据大小: ${dataSizeMB} MB (${dataSize} 字节)`);

    // Gitee 限制单个文件最大 1MB
    if (platform === 'gitee' && dataSize > 1024 * 1024) {
      throw new Error(`书签数据过大 (${dataSizeMB} MB),Gitee 限制单个文件最大 1MB。请考虑使用 GitHub 或减少书签数量。`);
    }

    // 根据平台执行同步
    let result;
    if (platform === 'github') {
      result = await syncToGithub(token, gistId, bookmarkData);
    } else if (platform === 'gitee') {
      result = await syncToGitee(token, gistId, bookmarkData);
    } else {
      throw new Error('不支持的同步平台');
    }

    // 保存同步状态(包括平台级别字段,便于 popup 显示)
    const now = Date.now();
    const storageData = {
      lastSyncTime: now,
      lastSyncCount: bookmarkCount,
      syncStatus: 'success'
    };

    if (platform === 'github') {
      storageData.githubGistId = result.gistId;
      storageData.githubRemoteCount = bookmarkCount;
      storageData.githubSyncStatus = 'success';
      storageData.githubLastSyncTime = now;
      storageData.githubLastSyncCount = bookmarkCount;
    } else {
      storageData.giteeGistId = result.gistId;
      storageData.giteeRemoteCount = bookmarkCount;
      storageData.giteeSyncStatus = 'success';
      storageData.giteeLastSyncTime = now;
      storageData.giteeLastSyncCount = bookmarkCount;
    }

    await chrome.storage.local.set(storageData);

    // 已经同步成功,清除未同步标记并更新角标
    try {
      await chrome.storage.local.set({ hasUnsynced: false });
      await updateActionBadge();
    } catch (e) {
      console.warn('同步成功后清除未同步标记失败:', e);
    }

    // 追加同步历史并通知 popup(如果打开)
    try {
      const history = await chrome.storage.local.get(['syncHistory']);
      const list = history.syncHistory || [];
      list.unshift({ platform, action: 'upload', status: 'success', time: now, count: bookmarkCount });
      await chrome.storage.local.set({ syncHistory: list.slice(0, 50) });
    } catch (e) {
      console.warn('记录同步历史失败:', e);
    }

    try {
      chrome.runtime.sendMessage({ action: 'platformSyncUpdate', platform, status: 'success', time: now, count: bookmarkCount, type: 'upload' }).catch(() => {});
    } catch (e) { /* ignore */ }

    console.log('同步成功:', result);
    return { gistId: result.gistId, url: result.url, updatedAt: result.updatedAt, count: bookmarkCount };
  } catch (error) {
    console.error('同步失败:', error);

    // 保存失败状态(同时写入平台级错误状态)
    try {
      const errData = { syncStatus: 'error' };
      const nowErr = Date.now();
      if (platform === 'github') {
        errData.githubSyncStatus = 'error';
        errData.githubLastSyncTime = nowErr;
      } else if (platform === 'gitee') {
        errData.giteeSyncStatus = 'error';
        errData.giteeLastSyncTime = nowErr;
      }
      await chrome.storage.local.set(errData);

      // 追加失败历史并通知 popup
      try {
        const history = await chrome.storage.local.get(['syncHistory']);
        const list = history.syncHistory || [];
        list.unshift({ platform, action: 'upload', status: 'error', time: nowErr, count: bookmarkCount });
        await chrome.storage.local.set({ syncHistory: list.slice(0, 50) });
      } catch (e) {
        console.warn('记录失败同步历史失败:', e);
      }

      try {
        chrome.runtime.sendMessage({ action: 'platformSyncUpdate', platform, status: 'error', time: nowErr, count: bookmarkCount, type: 'upload' }).catch(() => {});
      } catch (e) { /* ignore */ }
    } catch (e) {
      console.warn('记录后台同步错误状态失败:', e);
    }

    throw error;
  }
}



// 验证 Token 并获取当前用户信息
async function verifyToken(platform) {
  const cfg = await chrome.storage.local.get(['githubToken', 'giteeToken']);
  const token = platform === 'github' ? cfg.githubToken : platform === 'gitee' ? cfg.giteeToken : null;
  if (!token) throw new Error('未配置 Token');
  if (platform === 'github') return await verifyGithubToken(token);
  if (platform === 'gitee') return await verifyGiteeToken(token);
  throw new Error('不支持的平台');
}
async function verifyGithubToken(token) {
  const r = await fetch('https://api.github.com/user', {
    headers: { 'Authorization': 'Bearer ' + token, 'Accept': 'application/vnd.github.v3+json' }
  });
  if (!r.ok) {
    const t = await r.text().catch(() => '');
    throw new Error('GitHub 验证失败: ' + r.status + (t ? ' ' + t.slice(0, 120) : ''));
  }
  const u = await r.json();
  return {
    name: u.name || u.login || 'GitHub 用户',
    login: u.login || '',
    avatarUrl: u.avatar_url || ''
  };
}
async function verifyGiteeToken(token) {
  const r = await fetch('https://gitee.com/api/v5/user?access_token=' + encodeURIComponent(token));
  if (!r.ok) {
    const t = await r.text().catch(() => '');
    throw new Error('Gitee 验证失败: ' + r.status + (t ? ' ' + t.slice(0, 120) : ''));
  }
  const u = await r.json();
  return {
    name: u.name || u.login || 'Gitee 用户',
    login: u.login || '',
    avatarUrl: u.avatar_url || ''
  };
}

// 同步到 GitHub Gist
async function syncToGithub(token, gistId, bookmarkData) {
  const url = gistId
    ? `https://api.github.com/gists/${gistId}`
    : 'https://api.github.com/gists';

  const method = gistId ? 'PATCH' : 'POST';

  const body = {
    description: 'MiniBookmark',
    public: false,
    files: {
      'bookmarks.json': {
        content: JSON.stringify(bookmarkData, null, 2)
      }
    }
  };

  const response = await fetch(url, {
    method: method,
    headers: {
      'Authorization': `Bearer ${token}`,
      'Accept': 'application/vnd.github.v3+json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(body)
  });

  if (!response.ok) {
    const errorText = await response.text();
    let errorMsg;
    try {
      const error = JSON.parse(errorText);
      errorMsg = error.message || error.error || `GitHub API 错误: ${response.status}`;
    } catch (e) {
      errorMsg = `GitHub API 错误: ${response.status} - ${errorText}`;
    }
    console.error('GitHub API 错误详情:', errorMsg);
    throw new Error(errorMsg);
  }

  const result = await response.json();
  return {
    gistId: result.id,
    url: result.html_url,
    updatedAt: result.updated_at
  };
}

// 同步到 Gitee
// Gitee 的 code_pieces.content 字段使用 utf8(3 字节),无法存储 4 字节 UTF-8(大部分 emoji),
// 直接写入会报 Mysql2::Error: Incorrect string value。上传前需剥离这类字符。
function sanitizeForGitee(text) {
  if (typeof text !== 'string') return text;
  // 移除 U+10000 及以上的补充平面字符(即 4 字节 UTF-8)
  return text.replace(/[\u{10000}-\u{10FFFF}]/gu, '');
}

async function syncToGitee(token, gistId, bookmarkData) {
  console.log('开始同步到 Gitee...');
  // 剥离 4 字节 UTF-8 字符,避免 Gitee 数据库写入失败
  const safeContent = sanitizeForGitee(JSON.stringify(bookmarkData));
  const auth = `?access_token=${encodeURIComponent(token)}`;
  const headers = { 'Content-Type': 'application/json' };
  const patchBody = JSON.stringify({
    files: { 'bookmarks.json': { content: safeContent, filename: 'bookmarks.json' } }
  });
  const patchGist = async (id) => {
    const r = await fetch(`https://gitee.com/api/v5/gists/${id}${auth}`, {
      method: 'PATCH', headers, body: patchBody
    });
    if (r.ok) {
      const res = await r.json();
      return res;
    }
    console.warn('Gitee 更新失败(尝试下一候选):', r.status, await r.text().catch(() => ''));
    return null;
  };

  // 需要尝试更新的目标:记录的 gistId 优先;失效(如 404 {"message":"Gist"})
  // 则查询列表,取“最新的一份”继续更新,避免反复新建产生重复
  const targets = [];
  if (gistId) targets.push(gistId);
  try {
    const list = await fetchGiteeGists(token);
    const candidates = (list || [])
      .filter(g => g.files && g.files['bookmarks.json'])
      .sort((a, b) =>
        new Date(b.updated_at || b.created_at || 0).getTime() -
        new Date(a.updated_at || a.created_at || 0).getTime()
      );
    if (candidates[0]) targets.push(candidates[0].id);
  } catch (e) {
    console.warn('获取 Gitee 片段列表失败(将仅尝试记录的 gistId):', e);
  }

  // 去重后依次尝试 PATCH 更新
  const tried = new Set();
  for (const id of targets) {
    if (!id || tried.has(id)) continue;
    tried.add(id);
    try {
      const res = await patchGist(id);
      if (res) {
        console.log('Gitee 更新成功,Gist ID:', res.id);
        return { gistId: res.id, url: res.html_url, updatedAt: res.updated_at };
      }
    } catch (e) {
      console.warn('Gitee 更新异常(尝试下一候选):', e);
    }
  }

  // 没有任何可更新的现有片段:新建一份
  console.log('未找到可更新片段,新建 Gist...');
  const createResponse = await fetch(`https://gitee.com/api/v5/gists${auth}`, {
    method: 'POST',
    headers,
    body: JSON.stringify({
      files: {
        'bookmarks.json': {
          content: safeContent
        }
      },
      description: 'MiniBookmark',
      public: false
    })
  });

  if (!createResponse.ok) {
    const errorText = await createResponse.text();
    console.error('创建 Gist 失败:', errorText);
    throw new Error(`Gitee 创建 Gist 失败: ${createResponse.status} ${errorText}`);
  }

  const createResult = await createResponse.json();
  if (!createResult || !createResult.id) {
    throw new Error('Gitee 创建 Gist 失败:响应中缺少 Gist ID');
  }
  console.log('Gitee 新建成功,Gist ID:', createResult.id);
  return {
    gistId: createResult.id,
    url: createResult.html_url,
    updatedAt: createResult.updated_at
  };
}

// 将远端书签按 URL / 标题去重后合并进本地(不删除本地已有项)
async function mergeIntoLocal(remoteNodes, parentId) {
  if (!Array.isArray(remoteNodes) || !parentId) return;
  let existing = [];
  try { existing = await chrome.bookmarks.getChildren(parentId); } catch (e) { return; }
  const existingByKey = new Map();
  for (const n of existing) {
    const key = n.url ? ('u:' + n.url) : ('f:' + (n.title || ''));
    if (!existingByKey.has(key)) existingByKey.set(key, n);
  }
  for (const r of remoteNodes) {
    const key = r.url ? ('u:' + r.url) : ('f:' + (r.title || ''));
    const found = existingByKey.get(key);
    if (found) {
      // 文件夹则继续向下合并;书签(叶子)已存在则跳过
      if (!r.url && r.children && found.url === undefined) {
        await mergeIntoLocal(r.children, found.id);
      }
      continue;
    }
    try {
      if (r.url) {
        await chrome.bookmarks.create({ parentId, title: r.title || '', url: r.url });
      } else {
        const folder = await chrome.bookmarks.create({ parentId, title: r.title || '文件夹' });
        if (r.children) await mergeIntoLocal(r.children, folder.id);
      }
    } catch (e) {
      console.warn('合并创建书签失败:', e);
    }
  }
}

// 将远端整棵书签树合并进本地(按顶层文件夹标题匹配)
async function mergeRemoteIntoLocal(remoteBookmarks) {
  if (!remoteBookmarks || !remoteBookmarks[0]) return;
  const localTree = await chrome.bookmarks.getTree();
  const localRoot = localTree[0];
  for (const remoteTop of (remoteBookmarks[0].children || [])) {
    let localTop = (localRoot.children || []).find(c => !c.url && c.title === remoteTop.title);
    if (!localTop) {
      try {
        localTop = await chrome.bookmarks.create({ parentId: localRoot.id, title: remoteTop.title || '文件夹' });
      } catch (e) { console.warn('创建顶层文件夹失败:', e); continue; }
    }
    await mergeIntoLocal(remoteTop.children || [], localTop.id);
  }
}

// 获取远端书签数据,供合并使用
async function fetchRemoteBookmarkData(platform) {
  const config = await chrome.storage.local.get([
    'githubToken', 'giteeToken', 'githubGistId', 'giteeGistId'
  ]);
  const token = platform === 'github' ? config.githubToken : config.giteeToken;
  const gistId = platform === 'github' ? config.githubGistId : config.giteeGistId;
  if (!token || !gistId) return null;
  try {
    return platform === 'github' ? await fetchFromGithub(token, gistId) : await fetchFromGitee(token, gistId);
  } catch (e) {
    console.warn('获取远端书签数据失败:', e);
    return null;
  }
}

// 将书签树扁平化为条目列表(含路径),供对比/合并使用
// 每个条目额外带上 orderKey(含层级顺序的签名),用于检测"书签被移动/重新排序"等结构性变化
function flattenBookmarks(treeNode, folderPath = '', orderPrefix = '', index = 0, out = []) {
  const children = Array.isArray(treeNode) ? treeNode : (treeNode && treeNode.children) || [];
  children.forEach((node, i) => {
    const title = node.title || '';
    const path = folderPath ? `${folderPath} / ${title}` : title;
    // 顺序签名:父级顺序链 + 自身在兄弟中的序号 + url(叶子才有 url)
    const orderKey = `${orderPrefix}${i}.${node.url ? node.url : title}`;
    if (node.url) {
      out.push({ title, url: node.url, folderPath: path, orderKey });
    }
    if (node.children) {
      flattenBookmarks(node.children, path, orderKey + '/', 0, out);
    }
  });
  return out;
}

// 分析本地与远端书签的差距
async function analyzeSyncStatus(platform) {
  const localTree = await chrome.bookmarks.getTree();
  const localFlat = flattenBookmarks(localTree);
  let remoteFlat = [];
  let remoteError = null;
  try {
    const remoteData = await fetchRemoteBookmarkData(platform);
    if (remoteData && remoteData.bookmarks) {
      remoteFlat = flattenBookmarks(remoteData.bookmarks);
    }
  } catch (e) {
    remoteError = e.message || String(e);
  }
  const localUrls = new Set(localFlat.filter(b => b.url).map(b => b.url));
  const remoteUrls = new Set(remoteFlat.filter(b => b.url).map(b => b.url));
  const localOnlyItems = localFlat.filter(b => b.url && !remoteUrls.has(b.url));
  const remoteOnlyItems = remoteFlat.filter(b => b.url && !localUrls.has(b.url));
  const bothCount = localFlat.filter(b => b.url && remoteUrls.has(b.url)).length;
  // 仅针对两端都存在的 URL,比较其所在层次/顺序是否一致(排序、移动均会触发)
  const remoteByUrl = new Map();
  for (const b of remoteFlat) {
    if (!remoteByUrl.has(b.url)) remoteByUrl.set(b.url, b.orderKey);
  }
  const orderChangedItems = localFlat.filter(b => {
    if (!b.url || !remoteUrls.has(b.url)) return false;
    return remoteByUrl.get(b.url) !== b.orderKey;
  }).map(b => {
    const remote = remoteFlat.find(r => r.url === b.url);
    return { ...b, remoteFolderPath: remote ? remote.folderPath : '' };
  });
  const orderChangedCount = orderChangedItems.length;
  const SAMPLE = 50;
  return {
    platform,
    localCount: localFlat.length,
    remoteCount: remoteFlat.length,
    localOnlyCount: localOnlyItems.length,
    remoteOnlyCount: remoteOnlyItems.length,
    bothCount,
    orderChangedCount,
    remoteError,
    localOnlyItems: localOnlyItems.slice(0, SAMPLE),
    remoteOnlyItems: remoteOnlyItems.slice(0, SAMPLE),
    orderChangedItems: orderChangedItems.slice(0, SAMPLE),
    localOnlyTotal: localOnlyItems.length,
    remoteOnlyTotal: remoteOnlyItems.length,
    orderChangedTotal: orderChangedItems.length,
    hasMoreLocal: localOnlyItems.length > SAMPLE,
    hasMoreRemote: remoteOnlyItems.length > SAMPLE,
    hasMoreOrder: orderChangedItems.length > SAMPLE,
  };
}

// 从远端恢复书签
async function restoreFromRemote(platform) {
  try {
    const config = await chrome.storage.local.get([
      'githubToken',
      'giteeToken',
      'githubGistId',
      'giteeGistId'
    ]);

    const token = platform === 'github' ? config.githubToken : config.giteeToken;
    const gistId = platform === 'github' ? config.githubGistId : config.giteeGistId;

    if (!gistId) {
      throw new Error('没有找到远端备份');
    }

    // 获取远程书签数据
    let bookmarkData;
    if (platform === 'github') {
      bookmarkData = await fetchFromGithub(token, gistId);
    } else if (platform === 'gitee') {
      bookmarkData = await fetchFromGitee(token, gistId);
    }

    console.log('获取到远端书签数据:', bookmarkData);
    console.log('书签结构:', JSON.stringify(bookmarkData.bookmarks, null, 2).substring(0, 500));

    // 合并模式:不清空本地,直接把远端合并进本地后返回
    const syncMode = (await chrome.storage.local.get(['syncMode'])).syncMode;
    if (syncMode === 'merge') {
      if (bookmarkData && bookmarkData.bookmarks) {
        await mergeRemoteIntoLocal(bookmarkData.bookmarks);
        const mergedCount = bookmarkData.count || 0;
        console.log('合并模式:已把远端书签合并进本地,完成恢复');
        // 写入状态/历史/通知,与覆盖模式保持一致
        try {
          const now = Date.now();
          const data = {
            lastSyncTime: now,
            lastSyncCount: mergedCount,
            syncStatus: 'success'
          };
          if (platform === 'github') {
            data.githubSyncStatus = 'success';
            data.githubLastSyncTime = now;
            data.githubLastSyncCount = mergedCount;
          } else if (platform === 'gitee') {
            data.giteeSyncStatus = 'success';
            data.giteeLastSyncTime = now;
            data.giteeLastSyncCount = mergedCount;
          }
          await chrome.storage.local.set(data);
          try {
            const history = await chrome.storage.local.get(['syncHistory']);
            const list = history.syncHistory || [];
            list.unshift({ platform, action: 'download', status: 'success', time: now, count: mergedCount });
            await chrome.storage.local.set({ syncHistory: list.slice(0, 50) });
          } catch (e) { /* ignore */ }
          try {
            chrome.runtime.sendMessage({ action: 'platformSyncUpdate', platform, status: 'success', time: now, count: mergedCount, type: 'download' }).catch(() => {});
          } catch (e) { /* ignore */ }
        } catch (e) { /* ignore */ }
        return { count: mergedCount };
      }
    }

    // 删除本地所有书签(除了书签栏和其他书签文件夹)
    const tree = await chrome.bookmarks.getTree();
    const root = tree[0];

    console.log('开始清空本地书签...');
    // 清空书签栏和其他书签
    if (root.children) {
      for (const folder of root.children) {
        if (folder.children) {
          // 删除文件夹内的所有子项
          for (const child of folder.children) {
            try {
              if (child.children) {
                await chrome.bookmarks.removeTree(child.id);
              } else {
                await chrome.bookmarks.remove(child.id);
              }
            } catch (e) {
              console.warn('删除书签失败:', e);
            }
          }
        }
      }
    }
    console.log('本地书签已清空');

    // 恢复书签
    if (bookmarkData.bookmarks && bookmarkData.bookmarks[0]) {
      console.log('开始恢复书签...');
      // 获取当前的书签根节点
      const currentTree = await chrome.bookmarks.getTree();
      const currentRoot = currentTree[0];

      console.log('当前书签根节点:', currentRoot);
      console.log('远程书签根节点:', bookmarkData.bookmarks[0]);

      // 恢复书签到对应的文件夹
      if (currentRoot.children && bookmarkData.bookmarks[0].children) {
        const remoteFolders = bookmarkData.bookmarks[0].children;
        for (let i = 0; i < remoteFolders.length; i++) {
          const remoteFolder = remoteFolders[i];
          console.log('处理远程文件夹:', remoteFolder.title);
          // 优先按标题匹配本地文件夹(书签栏、其他书签);
          // 跨语言/跨浏览器时标题不同,回退到固定位置(children[0]=书签栏, [1]=其他书签)
          let localFolder = currentRoot.children.find(f => f.title === remoteFolder.title);
          if (!localFolder && currentRoot.children[i]) {
            localFolder = currentRoot.children[i];
          }
          if (localFolder && remoteFolder.children) {
            console.log('找到本地文件夹:', localFolder.title, 'ID:', localFolder.id);
            console.log('远程文件夹有', remoteFolder.children.length, '个子项');
            await restoreBookmarkTree(remoteFolder, localFolder.id);
          } else {
            console.warn('未找到本地文件夹:', remoteFolder.title);
          }
        }
      }
      console.log('书签恢复完成');
    } else {
      console.error('远程书签数据格式错误');
    }

    // 保存恢复状态(包含平台级字段)
    try {
      const now = Date.now();
      const data = {
        lastSyncTime: now,
        lastSyncCount: bookmarkData.count || 0,
        syncStatus: 'success'
      };
      if (platform === 'github') {
        data.githubSyncStatus = 'success';
        data.githubLastSyncTime = now;
        data.githubLastSyncCount = bookmarkData.count || 0;
      } else if (platform === 'gitee') {
        data.giteeSyncStatus = 'success';
        data.giteeLastSyncTime = now;
        data.giteeLastSyncCount = bookmarkData.count || 0;
      }
      await chrome.storage.local.set(data);

      // 追加恢复历史并通知 popup
      try {
        const history = await chrome.storage.local.get(['syncHistory']);
        const list = history.syncHistory || [];
        list.unshift({ platform, action: 'download', status: 'success', time: now, count: bookmarkData.count || 0 });
        await chrome.storage.local.set({ syncHistory: list.slice(0, 50) });
      } catch (e) {
        console.warn('记录恢复历史失败:', e);
      }

      try {
        chrome.runtime.sendMessage({ action: 'platformSyncUpdate', platform, status: 'success', time: now, count: bookmarkData.count || 0, type: 'download' }).catch(() => {});
      } catch (e) { /* ignore */ }
    } catch (e) {
      console.warn('保存恢复状态失败:', e);
    }

    return { count: bookmarkData.count || 0 };
  } catch (error) {
    console.error('恢复书签失败:', error);
    // 记录恢复失败的平台状态并写历史,便于 UI 提示
    try {
      const nowErr = Date.now();
      const errData = { syncStatus: 'error' };
      if (platform === 'github') {
        errData.githubSyncStatus = 'error';
        errData.githubLastSyncTime = nowErr;
      } else if (platform === 'gitee') {
        errData.giteeSyncStatus = 'error';
        errData.giteeLastSyncTime = nowErr;
      }
      await chrome.storage.local.set(errData);

      try {
        const history = await chrome.storage.local.get(['syncHistory']);
        const list = history.syncHistory || [];
        list.unshift({ platform, action: 'download', status: 'error', time: nowErr, count: bookmarkData && bookmarkData.count ? bookmarkData.count : 0 });
        await chrome.storage.local.set({ syncHistory: list.slice(0, 50) });
      } catch (e) {
        console.warn('记录恢复失败历史失败:', e);
      }

      try {
        chrome.runtime.sendMessage({ action: 'platformSyncUpdate', platform, status: 'error', time: nowErr, count: bookmarkData && bookmarkData.count ? bookmarkData.count : 0, type: 'download' }).catch(() => {});
      } catch (e) { /* ignore */ }
    } catch (e) {
      console.warn('记录后台恢复错误状态失败:', e);
    }

    throw error;
  }
}

// 清空本地所有书签(保留"书签栏""其他书签"等根文件夹)
async function clearLocalBookmarks() {
  const tree = await chrome.bookmarks.getTree();
  const root = tree[0];
  if (!root || !root.children) return;
  for (const folder of root.children) {
    if (!folder.children) continue;
    for (const child of folder.children) {
      try {
        if (child.children) {
          await chrome.bookmarks.removeTree(child.id);
        } else {
          await chrome.bookmarks.remove(child.id);
        }
      } catch (e) {
        console.warn('删除书签失败:', e);
      }
    }
  }
}

// 递归恢复书签树
async function restoreBookmarkTree(node, parentId) {
  if (!node.children) {
    return;
  }

  for (const child of node.children) {
    try {
      if (child.url) {
        // 创建书签
        await chrome.bookmarks.create({
          parentId: parentId,
          title: child.title,
          url: child.url
        });
      } else if (child.children) {
        // 创建文件夹
        const folder = await chrome.bookmarks.create({
          parentId: parentId,
          title: child.title
        });
        // 递归创建子项(防止 folder.id 缺失导致崩溃)
        if (folder && folder.id) {
          await restoreBookmarkTree(child, folder.id);
        }
      }
    } catch (e) {
      console.warn('恢复书签项失败:', e, child);
    }
  }
}

// 从 GitHub 获取
async function fetchFromGithub(token, gistId) {
  const response = await fetch(`https://api.github.com/gists/${gistId}`, {
    headers: {
      'Authorization': `Bearer ${token}`,
      'Accept': 'application/vnd.github.v3+json'
    }
  });

  if (!response.ok) {
    throw new Error(`GitHub API 错误: ${response.status}`);
  }

  const result = await response.json();
  const content = result.files['bookmarks.json'].content;
  return JSON.parse(content);
}

// 从 Gitee 获取
async function fetchFromGitee(token, gistId) {
  const response = await fetch(`https://gitee.com/api/v5/gists/${gistId}?access_token=${token}`);

  if (!response.ok) {
    throw new Error(`Gitee API 错误: ${response.status}`);
  }

  const result = await response.json();
  const content = result.files['bookmarks.json'].content;
  return JSON.parse(content);
}

// 计算书签数量
function countBookmarks(node) {
  let count = 0;
  if (node.url) {
    count = 1;
  }
  if (node.children) {
    for (const child of node.children) {
      count += countBookmarks(child);
    }
  }
  return count;
}

// 获取远程书签数量
async function getRemoteBookmarkCount(platform) {
  try {
    const config = await chrome.storage.local.get([
      'githubToken',
      'giteeToken',
      'githubGistId',
      'giteeGistId'
    ]);

    const token = platform === 'github' ? config.githubToken : config.giteeToken;
    const gistId = platform === 'github' ? config.githubGistId : config.giteeGistId;

    if (!gistId) {
      return 0;
    }

    // 获取远程书签数据
    let bookmarkData;
    if (platform === 'github') {
      bookmarkData = await fetchFromGithub(token, gistId);
    } else if (platform === 'gitee') {
      bookmarkData = await fetchFromGitee(token, gistId);
    }

    return bookmarkData.count || 0;
  } catch (error) {
    console.error('获取远程书签数量失败:', error);
    return 0;
  }
}

// 查找已存在的 Gist
async function findExistingGist(platform) {
  try {
    const config = await chrome.storage.local.get(['githubToken', 'giteeToken']);

    if (!platform) {
      throw new Error('未指定平台');
    }

    const token = platform === 'github' ? config.githubToken : config.giteeToken;

    if (!token) {
      throw new Error(`未配置 ${platform === 'github' ? 'GitHub' : 'Gitee'} Token`);
    }

    let gistList;
    if (platform === 'github') {
      gistList = await fetchGithubGists(token);
    } else if (platform === 'gitee') {
      gistList = await fetchGiteeGists(token);
    }

    // 查找名为 bookmarks.json 的 Gist:若有多个,按更新时间倒序选最新的一个
    const bookmarkCandidates = (gistList || []).filter(gist => {
      return gist.files && gist.files['bookmarks.json'];
    });
    bookmarkCandidates.sort((a, b) => {
      const ta = new Date(a.updated_at || a.created_at || 0).getTime();
      const tb = new Date(b.updated_at || b.created_at || 0).getTime();
      return tb - ta;
    });
    const bookmarkGist = bookmarkCandidates[0] || null;

    if (bookmarkGist) {
      // 获取书签数据
      let bookmarkData;
      if (platform === 'github') {
        bookmarkData = await fetchFromGithub(token, bookmarkGist.id);
      } else {
        bookmarkData = await fetchFromGitee(token, bookmarkGist.id);
      }

      // 保存 gistId
      const storageData = {};
      if (platform === 'github') {
        storageData.githubGistId = bookmarkGist.id;
        storageData.githubRemoteCount = bookmarkData.count || 0;
      } else {
        storageData.giteeGistId = bookmarkGist.id;
        storageData.giteeRemoteCount = bookmarkData.count || 0;
      }

      await chrome.storage.local.set(storageData);

      return {
        gistId: bookmarkGist.id,
        count: bookmarkData.count || 0
      };
    } else {
      return {
        gistId: null,
        count: 0
      };
    }
  } catch (error) {
    console.error('查找已存在的 Gist 失败:', error);
    throw error;
  }
}

// 获取 GitHub Gists 列表
async function fetchGithubGists(token) {
  const response = await fetch('https://api.github.com/gists', {
    headers: {
      'Authorization': `Bearer ${token}`,
      'Accept': 'application/vnd.github.v3+json'
    }
  });

  if (!response.ok) {
    throw new Error(`GitHub API 错误: ${response.status}`);
  }

  return await response.json();
}

// 获取 Gitee Gists 列表
async function fetchGiteeGists(token) {
  const response = await fetch(`https://gitee.com/api/v5/gists?access_token=${token}`);

  if (!response.ok) {
    throw new Error(`Gitee API 错误: ${response.status}`);
  }

  return await response.json();
}

// 删除 GitHub Gist(仅本插件创建的备份片段)
async function deleteGithubGist(token, gistId) {
  const response = await fetch(`https://api.github.com/gists/${gistId}`, {
    method: 'DELETE',
    headers: {
      'Authorization': `Bearer ${token}`,
      'Accept': 'application/vnd.github.v3+json'
    }
  });
  // 成功返回 204;404 表示已被删除,可忽略
  if (!response.ok && response.status !== 404) {
    const t = await response.text().catch(() => '');
    throw new Error(`GitHub 删除 Gist 失败: ${response.status} ${t.slice(0, 120)}`);
  }
}

// 删除 Gitee Gist(仅本插件创建的备份片段)
async function deleteGiteeGist(token, gistId) {
  const response = await fetch(
    `https://gitee.com/api/v5/gists/${gistId}?access_token=${encodeURIComponent(token)}`,
    { method: 'DELETE' }
  );
  if (!response.ok && response.status !== 404) {
    const t = await response.text().catch(() => '');
    throw new Error(`Gitee 删除 Gist 失败: ${response.status} ${t.slice(0, 120)}`);
  }
}

// 清理同名旧 Gist,只保留最新一份
// 仅针对本插件创建、包含 bookmarks.json 文件的备份片段
async function cleanupOldGists(platform) {
  try {
    const config = await chrome.storage.local.get([
      'githubToken', 'giteeToken', 'githubGistId', 'giteeGistId'
    ]);
    const token = platform === 'github' ? config.githubToken : config.giteeToken;
    if (!token) return;

    const list = platform === 'github'
      ? await fetchGithubGists(token)
      : await fetchGiteeGists(token);

    const candidates = (list || []).filter(g => g.files && g.files['bookmarks.json']);
    if (candidates.length <= 1) return; // 不足两份无需清理

    // 按更新时间倒序,最新的排在最前
    candidates.sort((a, b) => {
      const ta = new Date(a.updated_at || a.created_at || 0).getTime();
      const tb = new Date(b.updated_at || b.created_at || 0).getTime();
      return tb - ta;
    });

    const keep = candidates[0];
    const remove = candidates.slice(1);
    let deleted = 0;

    for (const g of remove) {
      try {
        if (platform === 'github') await deleteGithubGist(token, g.id);
        else await deleteGiteeGist(token, g.id);
        deleted++;
        console.log(`[${platform}] 已删除旧片段: ${g.id}`);
      } catch (e) {
        console.warn(`[${platform}] 删除旧片段 ${g.id} 失败:`, e);
      }
    }

    // 若本地记录的 gistId 不是保留的最新一份,则更新
    const storedId = platform === 'github' ? config.githubGistId : config.giteeGistId;
    if (storedId !== keep.id) {
      const set = platform === 'github'
        ? { githubGistId: keep.id }
        : { giteeGistId: keep.id };
      await chrome.storage.local.set(set);
      console.log(`[${platform}] 更新本地记录 Gist 为最新: ${keep.id}`);
    }

    console.log(`[${platform}] 清理完成:保留 ${keep.id},删除 ${deleted} 个旧片段`);
  } catch (e) {
    console.warn(`[${platform}] 清理旧片段失败:`, e);
  }
}

// 启动时清理所有已配置平台的旧片段
async function cleanupOnStartup() {
  const config = await chrome.storage.local.get([
    'autoCleanupOldGists', 'githubToken', 'giteeToken'
  ]);
  if (config.autoCleanupOldGists === false) return; // 默认开启
  const platforms = [];
  if (config.githubToken) platforms.push('github');
  if (config.giteeToken) platforms.push('gitee');
  for (const p of platforms) {
    await cleanupOldGists(p);
  }
}