// MNote 主壳文件树运行时外置模块。
// 当前先承接 SIDEBAR_TREE_JS 中低风险的行数据解析 helper；
// inline script 保留 fallback，避免模块加载顺序影响首屏行为。

function fileTreeRowKind(row) {
  if (!(row instanceof HTMLElement)) return '';
  return String(row.getAttribute('data-row-kind') || '').trim();
}

function fileTreeRowDocumentId(row) {
  if (!(row instanceof HTMLElement)) return '';
  return String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim();
}

function fileTreeRowAssetId(row, deps) {
  if (!(row instanceof HTMLElement)) return '';
  var assetId = String(row.getAttribute('data-asset-id') || '').trim();
  if (assetId) return assetId;
  var currentSourceKind = deps && typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; };
  if (currentSourceKind() === 'local_folder' && fileTreeRowKind(row) === 'asset') {
    return String(row.getAttribute('data-row-id') || '').trim();
  }
  return '';
}

function decodeLocalEncodedPath(value) {
  var path = String(value || '').trim().replace(/~([0-9A-Fa-f]{2})/g, '%$1');
  if (!path) return '';
  try {
    return decodeURIComponent(path);
  } catch (_) {
    return path;
  }
}

function fileTreeRowLocalRelativePath(row, deps) {
  if (!(row instanceof HTMLElement)) return '';
  var direct = String(row.getAttribute('data-local-relative-path') || '').trim();
  if (direct) return direct;
  var localFilePathFromAssetId = deps && typeof deps.localFilePathFromAssetId === 'function'
    ? deps.localFilePathFromAssetId
    : function() { return ''; };
  var assetPath = localFilePathFromAssetId(fileTreeRowAssetId(row, deps));
  if (assetPath) return assetPath;
  var rowId = String(row.getAttribute('data-row-id') || '').trim();
  var nodeId = String(row.getAttribute('data-node-id') || '').trim();
  var documentId = fileTreeRowDocumentId(row);
  var kind = fileTreeRowKind(row);
  if (rowId.indexOf('local:asset:') === 0) return rowId.slice('local:asset:'.length);
  if (rowId.indexOf('local:markdown:') === 0) return rowId.slice('local:markdown:'.length);
  if (rowId.indexOf('local:folder:') === 0) return rowId.slice('local:folder:'.length);
  if (rowId.indexOf('local:node:') === 0) return rowId.slice('local:node:'.length);
  if (nodeId.indexOf('local:node:') === 0) return nodeId.slice('local:node:'.length);
  if ((kind === 'document' || kind === 'doc' || kind === 'markdown') && documentId.indexOf('local-md:') === 0) {
    return decodeLocalEncodedPath(documentId.slice('local-md:'.length));
  }
  if ((kind === 'folder' || kind === 'directory' || kind === 'index') && documentId.indexOf('local-dir:') === 0) {
    return decodeLocalEncodedPath(documentId.slice('local-dir:'.length));
  }
  return '';
}

function fileTreeRowLocalUploadTargetRelativePath(row, deps) {
  if (!(row instanceof HTMLElement)) return '';
  var kind = fileTreeRowKind(row);
  var relativePath = fileTreeRowLocalRelativePath(row, deps);
  if (!relativePath) return '';
  if (kind === 'folder' || kind === 'directory') return relativePath;
  var lastSlash = relativePath.lastIndexOf('/');
  return lastSlash >= 0 ? relativePath.slice(0, lastSlash) : '';
}

function isFileTreeDownloadableAssetRow(row, deps) {
  if (!(row instanceof HTMLElement)) return false;
  var kind = fileTreeRowKind(row);
  if (kind === 'document' || kind === 'doc' || kind === 'index' || kind === 'markdown' || kind === 'folder' || kind === 'directory') return false;
  return Boolean(fileTreeRowAssetId(row, deps));
}

function isFileTreeDownloadableRow(row, deps) {
  if (!(row instanceof HTMLElement)) return false;
  var currentSourceKind = deps && typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; };
  if (currentSourceKind() !== 'local_folder') return isFileTreeDownloadableAssetRow(row, deps);
  return Boolean(fileTreeRowLocalRelativePath(row, deps) || isFileTreeDownloadableAssetRow(row, deps));
}

function fileTreeAssetDownloadDetail(row, deps) {
  if (!isFileTreeDownloadableRow(row, deps)) return null;
  var rowTitle = deps && typeof deps.rowTitle === 'function' ? deps.rowTitle : function() { return ''; };
  var resolveWorkspaceId = deps && typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; };
  var title = rowTitle(row);
  var relativePath = fileTreeRowLocalRelativePath(row, deps);
  var assetId = fileTreeRowAssetId(row, deps) || (relativePath ? 'local-file:' + relativePath : '');
  return {
    contextKind: 'filetree',
    documentId: fileTreeRowDocumentId(row),
    rowId: row.getAttribute('data-row-id') || '',
    rowKind: fileTreeRowKind(row),
    assetId: assetId,
    localRelativePath: relativePath,
    title: title,
    fileName: title,
    workspaceId: resolveWorkspaceId(row)
  };
}

function fileTreeRowsByRowIds(rowIds, deps) {
  var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
  return (rowIds || []).map(function(rowId) {
    return document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(rowId) + '"]');
  }).filter(function(row) { return row instanceof HTMLElement; });
}

function fileTreeChildCount(documentId, deps) {
  if (!documentId) return 0;
  var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
  var row = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + documentId) + '"]');
  var node = row ? row.closest('.tree-node') : null;
  var children = node ? node.querySelectorAll(':scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"][data-row-kind="document"], :scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"][data-row-kind="doc"]') : [];
  return children.length;
}

function defaultEscapeHtml(value) {
  return String(value == null ? '' : value)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');
}

function defaultObjectIdentityAttr(identity) {
  try {
    return JSON.stringify(identity || {});
  } catch (_) {
    return '';
  }
}

function readProjection(value) {
  if (!value || typeof value !== 'object') return null;
  if (value.result && typeof value.result === 'object') return value.result;
  if (value.snapshot && value.snapshot.tree) return value.snapshot.tree;
  if (value.data && value.data.tree) return value.data.tree;
  if (value.tree && typeof value.tree === 'object') return value.tree;
  return value;
}

function readSidebarDataset(value) {
  if (!value || typeof value !== 'object') return null;
  if (value.snapshot && value.snapshot.dataset && typeof value.snapshot.dataset === 'object') return value.snapshot.dataset;
  if (value.data && value.data.dataset && typeof value.data.dataset === 'object') return value.data.dataset;
  if (value.dataset && typeof value.dataset === 'object') return value.dataset;
  if (value.sidebar && typeof value.sidebar === 'object') return value.sidebar;
  return null;
}

function readDatasetProjection(value, snakeCaseKey, camelCaseKey) {
  var dataset = readSidebarDataset(value);
  if (!dataset || typeof dataset !== 'object') return null;
  if (dataset[snakeCaseKey] && typeof dataset[snakeCaseKey] === 'object') return dataset[snakeCaseKey];
  if (dataset[camelCaseKey] && typeof dataset[camelCaseKey] === 'object') return dataset[camelCaseKey];
  return null;
}

function projectionItems(projection) {
  var resolved = readProjection(projection);
  return resolved && Array.isArray(resolved.items) ? resolved.items : [];
}

function hasProjectionItems(projection) {
  var resolved = readProjection(projection);
  return Boolean(resolved && Array.isArray(resolved.items));
}

function nodeIdOf(item) {
  return String(item && (item.nodeId || item.id || item.documentId) || '').trim();
}

function rowIdOf(item) {
  return String(item && (item.rowId || item.nodeId || item.id) || '').trim();
}

function parentIdOf(item) {
  return String(item && (item.parentNodeId || item.parentId || '') || '').trim();
}

function titleOf(item) {
  return String(item && item.title || '无标题').trim() || '无标题';
}

function fileWorkspaceRelativePath(item) {
  var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
  var workspacePath = meta.workspacePath && typeof meta.workspacePath === 'object' ? meta.workspacePath : {};
  var fromWorkspacePath = String(workspacePath.relativePath || '').trim();
  if (fromWorkspacePath) return fromWorkspacePath;
  var extra = meta.extra && typeof meta.extra === 'object' ? meta.extra : {};
  var source = extra.source && typeof extra.source === 'object' ? extra.source : {};
  var fromSource = String(source.relativePath || '').trim();
  if (fromSource) return fromSource;
  return String(item && (item.relativePath || item.rootRelativePath) || '').trim();
}

function groupRowsByParent(rows) {
  rows = Array.isArray(rows) ? rows : [];
  var ids = new Set(rows.map(nodeIdOf).filter(Boolean));
  var grouped = new Map();
  rows.forEach(function(item) {
    var parentId = parentIdOf(item);
    if (!ids.has(parentId)) parentId = '';
    if (!grouped.has(parentId)) grouped.set(parentId, []);
    grouped.get(parentId).push(item);
  });
  return grouped;
}

function replaceSidebarTreeFromDocument(nextDocument, rootId) {
  var current = document.getElementById(rootId);
  var next = nextDocument ? nextDocument.getElementById(rootId) : null;
  if (!(current instanceof HTMLElement) || !(next instanceof HTMLElement)) return false;
  current.innerHTML = next.innerHTML;
  Array.from(next.attributes || []).forEach(function(attr) {
    current.setAttribute(attr.name, attr.value);
  });
  return true;
}

function applyLocalFolderSidebarSnapshot(nextDocument, options) {
  options = options || {};
  var pageRootId = String(options.pageRootId || 'sidebar-tree-root');
  var fileRootId = String(options.fileRootId || 'sidebar-file-tree-root');
  var appliedPage = replaceSidebarTreeFromDocument(nextDocument, pageRootId);
  var appliedFile = replaceSidebarTreeFromDocument(nextDocument, fileRootId);
  var applied = appliedPage || appliedFile;
  if (applied && typeof options.onApplied === 'function') options.onApplied({
    pageRootApplied: appliedPage,
    fileRootApplied: appliedFile
  });
  return applied;
}

function markLocalFolderWatchApplied(value) {
  var appliedValue = String(value || 'projection');
  if (!document || !document.documentElement) return false;
  document.documentElement.setAttribute('data-mnote-local-folder-watch-applied', appliedValue);
  return true;
}

function revealFileTreeRow(row) {
  if (!(row instanceof HTMLElement)) return;
  var node = row.closest('.tree-node');
  while (node && node.parentElement) {
    if (node.parentElement.classList && node.parentElement.classList.contains('tree-children')) {
      node.parentElement.classList.remove('tree-children--collapsed');
      var parentNode = node.parentElement.closest('.tree-node');
      var parentRow = parentNode ? parentNode.querySelector(':scope > .tree-row') : null;
      if (parentRow instanceof HTMLElement) {
        parentRow.setAttribute('aria-expanded', 'true');
        var toggle = parentRow.querySelector('[data-rust-action="toggle"]');
        if (toggle) toggle.setAttribute('aria-expanded', 'true');
      }
    }
    node = node.parentElement.closest('.tree-node');
  }
  try { row.scrollIntoView({ block: 'nearest' }); } catch (_) {}
}

function revealFileTreeAssetRow(assetId, deps) {
  if (!assetId) return false;
  var cssEscape = deps && typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
  var row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(assetId) + '"]');
  if (!(row instanceof HTMLElement)) return false;
  revealFileTreeRow(row);
  return true;
}

function appendUploadedAssetRow(asset, documentId, deps) {
  deps = deps || {};
  var cssEscape = typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
  var escapeHtml = typeof deps.escapeHtml === 'function' ? deps.escapeHtml : defaultEscapeHtml;
  var objectIdentityAttr = typeof deps.objectIdentityAttr === 'function' ? deps.objectIdentityAttr : defaultObjectIdentityAttr;
  var uploadedAssetTitle = typeof deps.uploadedAssetTitle === 'function' ? deps.uploadedAssetTitle : function(nextAsset) {
    return String(nextAsset && (nextAsset.file_name || nextAsset.title || nextAsset.name) || '未命名附件').trim() || '未命名附件';
  };
  var uploadedAssetType = typeof deps.uploadedAssetType === 'function' ? deps.uploadedAssetType : function(nextAsset) {
    return String(nextAsset && (nextAsset.asset_type || nextAsset.assetType || nextAsset.mime_type || '') || '').trim();
  };
  var fileTreeIconKindForFileName = typeof deps.fileTreeIconKindForFileName === 'function' ? deps.fileTreeIconKindForFileName : function() { return ''; };
  var currentDocumentId = typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; };
  var currentSourceKind = typeof deps.currentSourceKind === 'function' ? deps.currentSourceKind : function() { return ''; };
  var assetId = String(asset && asset.id || '').trim();
  if (!assetId) return false;
  if (revealFileTreeAssetRow(assetId, { cssEscape: cssEscape })) return true;
  var objectKind = String(asset && (asset.objectKind || asset.resourceKind || '') || '').trim();
  if (!objectKind && (String(asset && (asset.asset_type || asset.assetType) || '').trim() === 'mindmap' || /\.mindmap\.json$/i.test(assetId))) {
    objectKind = 'mindmap';
  }
  var targetDocumentId = String(documentId || asset.document_id || asset.documentId || currentDocumentId() || '').trim();
  var parentRow = targetDocumentId
    ? document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + targetDocumentId) + '"]')
    : null;
  if (!parentRow && currentSourceKind() === 'local_folder' && objectKind === 'mindmap') return false;
  if (!parentRow) parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-kind="document"]');
  var root = document.querySelector('#sidebar-file-tree-root .tree-root');
  if (!root && !parentRow) return false;
  var parentLi = parentRow ? parentRow.closest('.tree-node') : null;
  var children = parentLi ? parentLi.querySelector(':scope > .tree-children') : null;
  if (parentLi && !children) {
    children = document.createElement('ul');
    children.className = 'tree-children';
    parentLi.appendChild(children);
  }
  if (children) {
    children.classList.remove('tree-children--collapsed');
    if (parentRow) {
      parentRow.setAttribute('aria-expanded', 'true');
      var toggle = parentRow.querySelector('[data-rust-action="toggle"]');
      if (toggle) toggle.setAttribute('aria-expanded', 'true');
    }
  }
  var container = children || root;
  var li = document.createElement('li');
  li.className = 'tree-node';
  var objectIdentity = {
    objectKind: objectKind || 'attachment',
    documentId: targetDocumentId || null,
    blockId: null,
    assetId: assetId
  };
  li.setAttribute('data-node-id', 'asset:' + assetId);
  var title = uploadedAssetTitle(asset);
  var iconKind = fileTreeIconKindForFileName(title) || uploadedAssetType(asset) || 'file';
  if (objectKind === 'mindmap') iconKind = 'mindmap';
  li.innerHTML =
    '<div class="tree-row" role="treeitem" aria-level="' + (parentRow ? '2' : '1') + '" aria-expanded="false" data-rust-rendered-row="filetree" data-testid="filetree-asset-row" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-row-kind="asset" data-node-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-doc-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-object-identity="' + escapeHtml(objectIdentityAttr(objectIdentity)) + '" data-object-kind="' + escapeHtml(objectKind || 'attachment') + '" data-shell-mode="filetree" data-selected="false" data-active="false" draggable="true">' +
    '<span class="tree-spacer" aria-hidden="true"></span><span class="tree-kind-badge" data-kind="' + escapeHtml(iconKind) + '" aria-hidden="true"></span>' +
    '<button type="button" class="tree-link" data-rust-action="open" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '"><span class="tree-link-title">' + escapeHtml(title) + '</span></button>' +
    '<div class="tree-actions"><button type="button" class="tree-action" data-testid="filetree-action-menu" data-rust-action="menu" data-row-id="' + escapeHtml('asset:' + assetId) + '" aria-label="更多操作">…</button></div></div>';
  container.appendChild(li);
  revealFileTreeRow(li.querySelector('.tree-row'));
  document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId);
  return true;
}

function fileTreeUploadTargetFallback(detail, deps) {
  detail = detail || {};
  deps = deps || {};
  var resolveWorkspaceId = typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; };
  var currentDocumentId = typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; };
  var workspaceId = String(detail.workspaceId || resolveWorkspaceId(document.body) || '').trim();
  var documentId = String(detail.documentId || currentDocumentId() || '').trim();
  if (Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
    return {
      workspaceId: workspaceId,
      targetDocumentId: documentId,
      targetMindmapId: null,
      targetSubPath: null,
      targetRelativePath: String(detail.targetRelativePath || ''),
      uploadIntent: String(detail.uploadIntent || 'filetree.folder.drop')
    };
  }
  if (!workspaceId || !documentId) {
    throw new Error('请选择一个目标页面后再拖入文件');
  }
  return {
    workspaceId: workspaceId,
    targetDocumentId: documentId,
    targetMindmapId: null,
    targetSubPath: null,
    uploadIntent: String(detail.uploadIntent || 'editor.markdown.attach')
  };
}

function normalizeFileTreeUploadTargetPlan(detail, plan) {
  detail = detail || {};
  plan = plan && typeof plan === 'object' ? Object.assign({}, plan) : {};
  if (Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
    plan.targetRelativePath = String(detail.targetRelativePath || '');
  }
  if (detail.uploadIntent) {
    plan.uploadIntent = String(detail.uploadIntent);
  } else if (Object.prototype.hasOwnProperty.call(detail, 'targetRelativePath')) {
    plan.uploadIntent = 'filetree.folder.drop';
  } else if (!plan.uploadIntent) {
    plan.uploadIntent = 'editor.markdown.attach';
  }
  return plan;
}

function fileTreeRowsForUploadPreflight(deps) {
  deps = deps || {};
  var fileTreeRowKind = typeof deps.fileTreeRowKind === 'function' ? deps.fileTreeRowKind : function(row) {
    return row instanceof HTMLElement ? String(row.getAttribute('data-row-kind') || '').trim() : '';
  };
  var fileTreeRowDocumentId = typeof deps.fileTreeRowDocumentId === 'function' ? deps.fileTreeRowDocumentId : function(row) {
    return row instanceof HTMLElement ? String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim() : '';
  };
  var fileTreeRowAssetId = typeof deps.fileTreeRowAssetId === 'function' ? deps.fileTreeRowAssetId : function(row) {
    return row instanceof HTMLElement ? String(row.getAttribute('data-asset-id') || '').trim() : '';
  };
  return Array.from(document.querySelectorAll('.tree-row[data-shell-mode="filetree"]')).map(function(row) {
    var documentId = fileTreeRowDocumentId(row);
    var assetId = fileTreeRowAssetId(row) || null;
    var badge = row.querySelector('.tree-kind-badge');
    return {
      rowId: row.getAttribute('data-row-id') || '',
      rowKind: fileTreeRowKind(row),
      documentId: documentId || null,
      assetId: assetId,
      assetDocumentId: documentId || null,
      assetType: badge ? badge.getAttribute('data-kind') : null,
      storagePath: null
    };
  }).filter(function(row) {
    return row.rowId || row.documentId || row.assetId;
  });
}

function fileTreeDocumentParentsForPreflight(deps) {
  deps = deps || {};
  var fileTreeRowDocumentId = typeof deps.fileTreeRowDocumentId === 'function' ? deps.fileTreeRowDocumentId : function(row) {
    return row instanceof HTMLElement ? String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim() : '';
  };
  return Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]')).map(function(row) {
    var documentId = fileTreeRowDocumentId(row);
    if (!documentId) return null;
    var parentRowId = row.getAttribute('data-parent-id') || '';
    var parentDocumentId = parentRowId.indexOf('doc:') === 0 ? parentRowId.slice(4) : parentRowId || null;
    return { documentId: documentId, parentId: parentDocumentId };
  }).filter(Boolean);
}

function fileTreeTargetChildrenForPreflight(targetRow, deps) {
  deps = deps || {};
  var fileTreeRowKind = typeof deps.fileTreeRowKind === 'function' ? deps.fileTreeRowKind : function(row) {
    return row instanceof HTMLElement ? String(row.getAttribute('data-row-kind') || '').trim() : '';
  };
  var fileTreeRowDocumentId = typeof deps.fileTreeRowDocumentId === 'function' ? deps.fileTreeRowDocumentId : function(row) {
    return row instanceof HTMLElement ? String(row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '').trim() : '';
  };
  var fileTreeRowAssetId = typeof deps.fileTreeRowAssetId === 'function' ? deps.fileTreeRowAssetId : function(row) {
    return row instanceof HTMLElement ? String(row.getAttribute('data-asset-id') || '').trim() : '';
  };
  var rowTitle = typeof deps.rowTitle === 'function' ? deps.rowTitle : function(row) {
    if (!(row instanceof HTMLElement)) return '';
    var titleNode = row.querySelector('.tree-link-title');
    return String(titleNode && titleNode.textContent || row.getAttribute('title') || '').trim();
  };
  var node = targetRow instanceof HTMLElement ? targetRow.closest('.tree-node') : null;
  if (!node) return [];
  return Array.from(node.querySelectorAll(':scope > .tree-children > .tree-node > .tree-row[data-shell-mode="filetree"]')).map(function(row) {
    return {
      rowKind: fileTreeRowKind(row),
      documentId: fileTreeRowDocumentId(row) || null,
      assetId: fileTreeRowAssetId(row) || null,
      title: rowTitle(row)
    };
  });
}

function fileTreeDropPreflightRows(deps) {
  deps = deps || {};
  var cssEscape = typeof deps.cssEscape === 'function' ? deps.cssEscape : function(value) { return String(value).replace(/["\\]/g, '\\$&'); };
  var rowTitle = typeof deps.rowTitle === 'function' ? deps.rowTitle : function(row) {
    if (!(row instanceof HTMLElement)) return '';
    var titleNode = row.querySelector('.tree-link-title');
    return String(titleNode && titleNode.textContent || row.getAttribute('title') || '').trim();
  };
  var rows = typeof deps.fileTreeRowsForUploadPreflight === 'function'
    ? deps.fileTreeRowsForUploadPreflight()
    : fileTreeRowsForUploadPreflight(deps);
  return rows.map(function(row) {
    var domRow = document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(row.rowId) + '"]');
    return Object.assign({}, row, { title: rowTitle(domRow) });
  });
}

function fileTreeDocumentWorkspacesForUploadPreflight(workspaceId, deps) {
  deps = deps || {};
  var rows = typeof deps.fileTreeRowsForUploadPreflight === 'function'
    ? deps.fileTreeRowsForUploadPreflight()
    : fileTreeRowsForUploadPreflight(deps);
  var seen = new Set();
  return rows.filter(function(row) {
    if (!row.documentId || seen.has(row.documentId)) return false;
    seen.add(row.documentId);
    return true;
  }).map(function(row) {
    return { documentId: row.documentId, workspaceId: workspaceId || null };
  });
}

function fileTreeUploadTargetPreflightBody(detail, deps) {
  detail = detail || {};
  deps = deps || {};
  var resolveWorkspaceId = typeof deps.resolveWorkspaceId === 'function' ? deps.resolveWorkspaceId : function() { return ''; };
  var currentDocumentId = typeof deps.currentDocumentId === 'function' ? deps.currentDocumentId : function() { return ''; };
  var workspaceId = String(detail.workspaceId || resolveWorkspaceId(document.body) || '').trim();
  var rows = typeof deps.fileTreeRowsForUploadPreflight === 'function'
    ? deps.fileTreeRowsForUploadPreflight()
    : fileTreeRowsForUploadPreflight(deps);
  var documentWorkspaces = fileTreeDocumentWorkspacesForUploadPreflight(workspaceId, Object.assign({}, deps, {
    fileTreeRowsForUploadPreflight: function() { return rows; }
  }));
  return {
    workspaceId: workspaceId || null,
    targetDocumentId: detail.documentId ? String(detail.documentId) : null,
    targetRowId: detail.targetRowId ? String(detail.targetRowId) : null,
    focusedRowId: deps.focusedRowId || null,
    activeDocumentId: currentDocumentId() || null,
    rows: rows,
    documentWorkspaces: documentWorkspaces
  };
}

function shortMindmapFileName(mindmapId) {
  var raw = String(mindmapId || '').trim();
  var pathName = raw.indexOf('/') >= 0 ? raw.split('/').pop() : raw;
  if (/\.json$/i.test(pathName)) return pathName;
  var digits = raw.match(/(\d{4,})$/);
  var suffix = digits ? digits[1].slice(-6) : '';
  return suffix ? '思维导图' + suffix + '.json' : '思维导图.json';
}

function parseMindmapApiTarget(input) {
  try {
    var rawUrl = typeof input === 'string'
      ? input
      : input && typeof input.url === 'string'
        ? input.url
        : '';
    if (!rawUrl) return null;
    var url = new URL(rawUrl, window.location.origin);
    var match = /^\/api\/mindmap\/([^/]+)\/([^/]+)$/.exec(url.pathname);
    if (!match) return null;
    return {
      documentId: decodeURIComponent(match[1]),
      mindmapId: decodeURIComponent(match[2])
    };
  } catch (_) {
    return null;
  }
}

function requestMethod(input, init) {
  return String(
    init && init.method
      ? init.method
      : input && typeof input.method === 'string'
        ? input.method
        : 'GET'
  ).toUpperCase();
}

function requestBodyHasMindmapCreateOnly(init) {
  var body = init && typeof init.body === 'string' ? init.body : '';
  if (!body) return false;
  try {
    var payload = JSON.parse(body);
    return payload && payload.createOnly === true;
  } catch (_) {
    return false;
  }
}

window.__mnoteFileTreeRuntime = {
  readProjection: readProjection,
  readSidebarDataset: readSidebarDataset,
  readDatasetProjection: readDatasetProjection,
  projectionItems: projectionItems,
  hasProjectionItems: hasProjectionItems,
  nodeIdOf: nodeIdOf,
  rowIdOf: rowIdOf,
  parentIdOf: parentIdOf,
  titleOf: titleOf,
  fileWorkspaceRelativePath: fileWorkspaceRelativePath,
  groupRowsByParent: groupRowsByParent,
  replaceSidebarTreeFromDocument: replaceSidebarTreeFromDocument,
  applyLocalFolderSidebarSnapshot: applyLocalFolderSidebarSnapshot,
  markLocalFolderWatchApplied: markLocalFolderWatchApplied,
  fileTreeRowKind: fileTreeRowKind,
  fileTreeRowDocumentId: fileTreeRowDocumentId,
  fileTreeRowAssetId: fileTreeRowAssetId,
  decodeLocalEncodedPath: decodeLocalEncodedPath,
  fileTreeRowLocalRelativePath: fileTreeRowLocalRelativePath,
  fileTreeRowLocalUploadTargetRelativePath: fileTreeRowLocalUploadTargetRelativePath,
  isFileTreeDownloadableAssetRow: isFileTreeDownloadableAssetRow,
  isFileTreeDownloadableRow: isFileTreeDownloadableRow,
  fileTreeAssetDownloadDetail: fileTreeAssetDownloadDetail,
  fileTreeRowsByRowIds: fileTreeRowsByRowIds,
  fileTreeChildCount: fileTreeChildCount,
  revealFileTreeRow: revealFileTreeRow,
  revealFileTreeAssetRow: revealFileTreeAssetRow,
  appendUploadedAssetRow: appendUploadedAssetRow,
  fileTreeUploadTargetFallback: fileTreeUploadTargetFallback,
  normalizeFileTreeUploadTargetPlan: normalizeFileTreeUploadTargetPlan,
  fileTreeRowsForUploadPreflight: fileTreeRowsForUploadPreflight,
  fileTreeDocumentParentsForPreflight: fileTreeDocumentParentsForPreflight,
  fileTreeTargetChildrenForPreflight: fileTreeTargetChildrenForPreflight,
  fileTreeDropPreflightRows: fileTreeDropPreflightRows,
  fileTreeDocumentWorkspacesForUploadPreflight: fileTreeDocumentWorkspacesForUploadPreflight,
  fileTreeUploadTargetPreflightBody: fileTreeUploadTargetPreflightBody,
  shortMindmapFileName: shortMindmapFileName,
  parseMindmapApiTarget: parseMindmapApiTarget,
  requestMethod: requestMethod,
  requestBodyHasMindmapCreateOnly: requestBodyHasMindmapCreateOnly
};
