import { ToolDef } from '../../llm/openai-compat.js';
import { logger } from '../../logger.js';
import {
  ToolContext,
  ToolResult,
  ToolsConfig,
  ALL_TOOL_DEFS,
  getToolDefs as getCoreToolDefs,
  executeCoreTools,
} from './core.js';
import { saveRawData, logRawDownload, RAW_SAVE_TOOLS, RAW_LOG_ONLY_TOOLS } from './raw-save.js';
import { saveStructuredBlocks } from './structured-blocks.js';
import type { McpAggregator } from '../../mcp/aggregator.js';
import type { McpRuntimeConfig } from '../../mcp/config.js';

export type { ToolContext, ToolResult, ToolsConfig };

let _mcpAggregator: McpAggregator | null = null;
export function setMcpAggregator(agg: McpAggregator | null): void {
  _mcpAggregator = agg;
}

type ExecuteCtxWithMcp = ToolContext & {
  ownerId?: string | null;
  jobId?: string | null;
  mcpConfig?: McpRuntimeConfig;
  mcpQuotaState?: { files: number; bytes: number };
};

// 外部モジュール（他チームが実装）のインターフェース型
interface ToolModule {
  TOOL_DEFS: Record<string, ToolDef>;
  executeTool(name: string, input: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult | null>;
}

// 外部モジュールを動的にロード（存在しない場合は null）
async function tryLoadModule(specifier: string): Promise<ToolModule | null> {
  try {
    const mod = await import(specifier) as ToolModule;
    return mod;
  } catch {
    return null;
  }
}

// 外部モジュールのキャッシュ
let _webModule: ToolModule | null | undefined = undefined;
let _imageModule: ToolModule | null | undefined = undefined;
let _dataModule: ToolModule | null | undefined = undefined;
let _officeModule: ToolModule | null | undefined = undefined;
let _reviewModule: ToolModule | null | undefined = undefined;
let _xModule: ToolModule | null | undefined = undefined;
let _orchestrationModule: ToolModule | null | undefined = undefined;
let _browserModule: ToolModule | null | undefined = undefined;
let _mapsModule: ToolModule | null | undefined = undefined;
let _youtubeModule: ToolModule | null | undefined = undefined;
let _piecesModule: ToolModule | null | undefined = undefined;
let _amazonModule: ToolModule | null | undefined = undefined;
let _speechModule: ToolModule | null | undefined = undefined;
let _checklistModule: ToolModule | null | undefined = undefined;
let _knowledgeModule: ToolModule | null | undefined = undefined;
let _msLearnModule: ToolModule | null | undefined = undefined;
let _slideModule: ToolModule | null | undefined = undefined;
let _userFolderModule: ToolModule | null | undefined = undefined;

async function getWebModule(): Promise<ToolModule | null> {
  if (_webModule === undefined) {
    _webModule = await tryLoadModule('./web.js');
    if (_webModule) logger.debug('[tools/index] web module loaded');
  }
  return _webModule;
}

async function getImageModule(): Promise<ToolModule | null> {
  if (_imageModule === undefined) {
    _imageModule = await tryLoadModule('./image.js');
    if (_imageModule) logger.debug('[tools/index] image module loaded');
  }
  return _imageModule;
}

async function getDataModule(): Promise<ToolModule | null> {
  if (_dataModule === undefined) {
    _dataModule = await tryLoadModule('./data.js');
    if (_dataModule) logger.debug('[tools/index] data module loaded');
  }
  return _dataModule;
}

async function getOfficeModule(): Promise<ToolModule | null> {
  if (_officeModule === undefined) {
    _officeModule = await tryLoadModule('./office.js');
    if (_officeModule) logger.debug('[tools/index] office module loaded');
  }
  return _officeModule;
}

async function getReviewModule(): Promise<ToolModule | null> {
  if (_reviewModule === undefined) {
    _reviewModule = await tryLoadModule('./review.js');
    if (_reviewModule) logger.debug('[tools/index] review module loaded');
  }
  return _reviewModule;
}

async function getXModule(): Promise<ToolModule | null> {
  if (_xModule === undefined) {
    _xModule = await tryLoadModule('./x.js');
    if (_xModule) logger.debug('[tools/index] x module loaded');
  }
  return _xModule;
}

async function getOrchestrationModule(): Promise<ToolModule | null> {
  if (_orchestrationModule === undefined) {
    _orchestrationModule = await tryLoadModule('./orchestration.js');
    if (_orchestrationModule) logger.debug('[tools/index] orchestration module loaded');
  }
  return _orchestrationModule;
}

async function getBrowserModule(): Promise<ToolModule | null> {
  if (_browserModule === undefined) {
    _browserModule = await tryLoadModule('./browser.js');
    if (_browserModule) logger.debug('[tools/index] browser module loaded');
  }
  return _browserModule;
}

async function getMapsModule(): Promise<ToolModule | null> {
  if (_mapsModule === undefined) {
    _mapsModule = await tryLoadModule('./maps.js');
    if (_mapsModule) logger.debug('[tools/index] maps module loaded');
  }
  return _mapsModule;
}

async function getYoutubeModule(): Promise<ToolModule | null> {
  if (_youtubeModule === undefined) {
    _youtubeModule = await tryLoadModule('./youtube.js');
    if (_youtubeModule) logger.debug('[tools/index] youtube module loaded');
  }
  return _youtubeModule;
}

async function getPiecesModule(): Promise<ToolModule | null> {
  if (_piecesModule === undefined) {
    _piecesModule = await tryLoadModule('./pieces.js');
    if (_piecesModule) logger.debug('[tools/index] pieces module loaded');
  }
  return _piecesModule;
}

async function getAmazonModule(): Promise<ToolModule | null> {
  if (_amazonModule === undefined) {
    _amazonModule = await tryLoadModule('./amazon.js');
    if (_amazonModule) logger.debug('[tools/index] amazon module loaded');
  }
  return _amazonModule;
}

async function getSpeechModule(): Promise<ToolModule | null> {
  if (_speechModule === undefined) {
    _speechModule = await tryLoadModule('./speech.js');
    if (_speechModule) logger.debug('[tools/index] speech module loaded');
  }
  return _speechModule;
}

async function getChecklistModule(): Promise<ToolModule | null> {
  if (_checklistModule === undefined) {
    _checklistModule = await tryLoadModule('./checklist.js');
    if (_checklistModule) logger.debug('[tools/index] checklist module loaded');
  }
  return _checklistModule;
}

async function getKnowledgeModule(): Promise<ToolModule | null> {
  if (_knowledgeModule === undefined) {
    _knowledgeModule = await tryLoadModule('./knowledge.js');
    if (_knowledgeModule) logger.debug('[tools/index] knowledge module loaded');
  }
  return _knowledgeModule;
}

async function getSlideModule(): Promise<ToolModule | null> {
  if (_slideModule === undefined) {
    _slideModule = await tryLoadModule('./slide.js');
    if (_slideModule) logger.debug('[tools/index] slide module loaded');
  }
  return _slideModule;
}

async function getMsLearnModule(): Promise<ToolModule | null> {
  if (_msLearnModule === undefined) {
    _msLearnModule = await tryLoadModule('./ms-learn.js');
    if (_msLearnModule) logger.debug('[tools/index] ms-learn module loaded');
  }
  return _msLearnModule;
}

let _docsModule: ToolModule | null | undefined;
async function getDocsModule(): Promise<ToolModule | null> {
  if (_docsModule === undefined) {
    _docsModule = await tryLoadModule('./docs.js');
    if (_docsModule) logger.debug('[tools/index] docs module loaded');
  }
  return _docsModule;
}

let _missionModule: ToolModule | null | undefined;
async function getMissionModule(): Promise<ToolModule | null> {
  if (_missionModule === undefined) {
    _missionModule = await tryLoadModule('./mission.js');
    if (_missionModule) logger.debug('[tools/index] mission module loaded');
  }
  return _missionModule;
}

async function getUserFolderModule(): Promise<ToolModule | null> {
  if (_userFolderModule === undefined) {
    _userFolderModule = await tryLoadModule('./user-folder.js');
    if (_userFolderModule) logger.debug('[tools/index] user-folder module loaded');
  }
  return _userFolderModule;
}

let _brainstormModule: ToolModule | null | undefined;
async function getBrainstormModule(): Promise<ToolModule | null> {
  if (_brainstormModule === undefined) {
    _brainstormModule = await tryLoadModule('./brainstorm.js');
    if (_brainstormModule) logger.debug('[tools/index] brainstorm module loaded');
  }
  return _brainstormModule;
}

let _appDocsModule: ToolModule | null | undefined;
async function getAppDocsModule(): Promise<ToolModule | null> {
  if (_appDocsModule === undefined) {
    _appDocsModule = await tryLoadModule('./app-docs.js');
    if (_appDocsModule) logger.debug('[tools/index] app-docs module loaded');
  }
  return _appDocsModule;
}

let _sshModule: ToolModule | null | undefined;
async function getSshModule(): Promise<ToolModule | null> {
  if (_sshModule === undefined) {
    _sshModule = await tryLoadModule('./ssh.js');
    if (_sshModule) logger.debug('[tools/index] ssh module loaded');
  }
  return _sshModule;
}

let _sshConsoleModule: ToolModule | null | undefined;
async function getSshConsoleModule(): Promise<ToolModule | null> {
  if (_sshConsoleModule === undefined) {
    _sshConsoleModule = await tryLoadModule('./ssh-console.js');
    if (_sshConsoleModule) logger.debug('[tools/index] ssh-console module loaded');
  }
  return _sshConsoleModule;
}

let _notesModule: ToolModule | null | undefined;
async function getNotesModule(): Promise<ToolModule | null> {
  if (_notesModule === undefined) {
    _notesModule = await tryLoadModule('./notes.js');
    if (_notesModule) logger.debug('[tools/index] notes module loaded');
  }
  return _notesModule;
}

let _dashboardModule: ToolModule | null | undefined = undefined;
async function getDashboardModule(): Promise<ToolModule | null> {
  if (_dashboardModule === undefined) {
    _dashboardModule = await tryLoadModule('./dashboard.js');
    if (_dashboardModule) logger.debug('[tools/index] dashboard module loaded');
  }
  return _dashboardModule;
}

/**
 * 全モジュールのツール定義を統合して返す。
 * allowedTools と editAllowed に応じてフィルタリングする。
 */
export async function getToolDefs(
  allowedTools: string[],
  editAllowed: boolean,
  options?: { vlmEnabled?: boolean; ownerId?: string | null; mcpDisabled?: boolean },
): Promise<ToolDef[]> {
  // 全ツール定義を収集
  const allDefs: Record<string, ToolDef> = { ...ALL_TOOL_DEFS };

  const webMod = await getWebModule();
  if (webMod) Object.assign(allDefs, webMod.TOOL_DEFS);

  const imageMod = await getImageModule();
  if (imageMod) Object.assign(allDefs, imageMod.TOOL_DEFS);

  const dataMod = await getDataModule();
  if (dataMod) Object.assign(allDefs, dataMod.TOOL_DEFS);

  const officeMod = await getOfficeModule();
  if (officeMod) Object.assign(allDefs, officeMod.TOOL_DEFS);

  const reviewMod = await getReviewModule();
  if (reviewMod) Object.assign(allDefs, reviewMod.TOOL_DEFS);

  const xMod = await getXModule();
  if (xMod) Object.assign(allDefs, xMod.TOOL_DEFS);

  const orchestrationMod = await getOrchestrationModule();
  if (orchestrationMod) Object.assign(allDefs, orchestrationMod.TOOL_DEFS);

  const browserMod = await getBrowserModule();
  if (browserMod) Object.assign(allDefs, browserMod.TOOL_DEFS);

  const mapsMod = await getMapsModule();
  if (mapsMod) Object.assign(allDefs, mapsMod.TOOL_DEFS);

  const youtubeMod = await getYoutubeModule();
  if (youtubeMod) Object.assign(allDefs, youtubeMod.TOOL_DEFS);

  const piecesMod = await getPiecesModule();
  if (piecesMod) Object.assign(allDefs, piecesMod.TOOL_DEFS);

  const amazonMod = await getAmazonModule();
  if (amazonMod) Object.assign(allDefs, amazonMod.TOOL_DEFS);

  const speechMod = await getSpeechModule();
  if (speechMod) Object.assign(allDefs, speechMod.TOOL_DEFS);

  const checklistMod = await getChecklistModule();
  if (checklistMod) Object.assign(allDefs, checklistMod.TOOL_DEFS);

  const knowledgeMod = await getKnowledgeModule();
  if (knowledgeMod) Object.assign(allDefs, knowledgeMod.TOOL_DEFS);

  const msLearnMod = await getMsLearnModule();
  if (msLearnMod) Object.assign(allDefs, msLearnMod.TOOL_DEFS);

  const slideMod = await getSlideModule();
  if (slideMod) Object.assign(allDefs, slideMod.TOOL_DEFS);

  const docsMod = await getDocsModule();
  if (docsMod) Object.assign(allDefs, docsMod.TOOL_DEFS);

  const missionMod = await getMissionModule();
  if (missionMod) Object.assign(allDefs, missionMod.TOOL_DEFS);

  const userFolderMod = await getUserFolderModule();
  if (userFolderMod) Object.assign(allDefs, userFolderMod.TOOL_DEFS);

  const brainstormMod = await getBrainstormModule();
  if (brainstormMod) Object.assign(allDefs, brainstormMod.TOOL_DEFS);

  const appDocsMod = await getAppDocsModule();
  if (appDocsMod) Object.assign(allDefs, appDocsMod.TOOL_DEFS);

  const sshMod = await getSshModule();
  if (sshMod) Object.assign(allDefs, sshMod.TOOL_DEFS);

  const sshConsoleMod = await getSshConsoleModule();
  if (sshConsoleMod) Object.assign(allDefs, sshConsoleMod.TOOL_DEFS);

  const notesMod = await getNotesModule();
  if (notesMod) Object.assign(allDefs, notesMod.TOOL_DEFS);

  const dashboardMod = await getDashboardModule();
  if (dashboardMod) Object.assign(allDefs, dashboardMod.TOOL_DEFS);

  const { TOOL_DEFS: skillToolDefs } = await import('./skills.js');
  Object.assign(allDefs, skillToolDefs);

  // メタツール: piece の allowed_tools に書かれていなくても常に利用可能
  // - ReadToolDoc: 全ツールのドキュメント参照
  // - CreateChecklist / CheckItem / GetChecklist: 進捗管理 (複数ステップタスクで使用)
  // - MissionUpdate: タスクの目標 / 進捗のピン止めメモを更新 (会話が長くなって
  //   最初の要件を見失わないため。常時上書き可能、未指定フィールドは保持)
  // - ListUserAssets / RunUserScript: ユーザーフォルダのスクリプト探索・実行
  // - Brainstorm: 着手前 or 行き詰まり時の多アプローチ比較 (issue #247)
  // - ReadAppDoc / ListAppDocs / GetMyOrchestratorState: Help アシスタント用 (#help piece)
  //   ただし他の piece からも参照できるようにメタ扱い
  const META_TOOLS = ['ReadToolDoc', 'CreateChecklist', 'CheckItem', 'GetChecklist', 'MissionUpdate', 'ListUserAssets', 'RunUserScript', 'UpdateUserMemory', 'ReadUserMemory', 'ReadUserTemplate', 'RenderUserTemplate', 'WriteUserScript', 'WriteUserTemplate', 'Brainstorm', 'ReadAppDoc', 'ListAppDocs', 'GetMyOrchestratorState', 'ReadSkill', 'ListSkills', 'InstallSkill'];
  const effectiveAllowed = [...allowedTools];
  for (const meta of META_TOOLS) {
    if (!effectiveAllowed.includes(meta) && meta in allDefs) {
      effectiveAllowed.push(meta);
    }
  }

  const staticDefs = effectiveAllowed
    .filter((name) => {
      if (!editAllowed && (name === 'Write' || name === 'Edit')) return false;
      if (!options?.vlmEnabled && name === 'ReadImage') return false;
      return name in allDefs;
    })
    .map((name) => allDefs[name]!);

  const mcpDefs =
    _mcpAggregator && options?.ownerId && !options?.mcpDisabled
      ? await _mcpAggregator.getToolDefs(options.ownerId, allowedTools)
      : [];

  return [...staticDefs, ...mcpDefs];
}

/**
 * ツールを実行する内部ルーター。
 * core → web → image → data の順で各モジュールに委譲し、
 * 最初に null でない結果を返したモジュールの結果を使う。
 */
async function executeToolInner(
  name: string,
  input: Record<string, unknown>,
  ctx: ToolContext,
): Promise<ToolResult> {
  if (name.startsWith('mcp__')) {
    if (ctx.mcpDisabled) {
      return { output: 'MCP tools are disabled for this task (options.mcpDisabled)', isError: true };
    }
    if (!_mcpAggregator) {
      return { output: 'MCP サブシステムが初期化されていません', isError: true };
    }
    const ctxWithMcp = ctx as ExecuteCtxWithMcp;
    if (!ctxWithMcp.mcpQuotaState) {
      ctxWithMcp.mcpQuotaState = { files: 0, bytes: 0 };
    }
    if (!ctxWithMcp.mcpConfig) {
      return { output: 'MCP 設定が ToolContext に伝播していません', isError: true };
    }
    const result = await _mcpAggregator.executeTool(name, input, {
      workspacePath: ctx.workspacePath,
      ownerId: ctxWithMcp.ownerId ?? '',
      jobId: ctxWithMcp.jobId ?? '',
      config: ctxWithMcp.mcpConfig,
      quotaState: ctxWithMcp.mcpQuotaState,
    });
    if (result === null) {
      return { output: `MCP ツール dispatch が ${name} に対して null を返しました`, isError: true };
    }
    return { output: result.output, isError: result.isError };
  }

  // core ツール
  const coreResult = await executeCoreTools(name, input, ctx);
  if (coreResult !== null) return coreResult;

  // web ツール
  const webMod = await getWebModule();
  if (webMod) {
    const webResult = await webMod.executeTool(name, input, ctx);
    if (webResult !== null) return webResult;
  }

  // image ツール
  const imageMod = await getImageModule();
  if (imageMod) {
    const imageResult = await imageMod.executeTool(name, input, ctx);
    if (imageResult !== null) return imageResult;
  }

  // data ツール
  const dataMod = await getDataModule();
  if (dataMod) {
    const dataResult = await dataMod.executeTool(name, input, ctx);
    if (dataResult !== null) return dataResult;
  }

  // office ツール
  const officeMod = await getOfficeModule();
  if (officeMod) {
    const officeResult = await officeMod.executeTool(name, input, ctx);
    if (officeResult !== null) return officeResult;
  }

  // review ツール
  const reviewMod = await getReviewModule();
  if (reviewMod) {
    const reviewResult = await reviewMod.executeTool(name, input, ctx);
    if (reviewResult !== null) return reviewResult;
  }

  // x tools
  const xMod = await getXModule();
  if (xMod) {
    const xResult = await xMod.executeTool(name, input, ctx);
    if (xResult !== null) return xResult;
  }

  // orchestration ツール
  const orchestrationMod = await getOrchestrationModule();
  if (orchestrationMod) {
    const orchestrationResult = await orchestrationMod.executeTool(name, input, ctx);
    if (orchestrationResult !== null) return orchestrationResult;
  }

  // browser ツール
  const browserMod = await getBrowserModule();
  if (browserMod) {
    const browserResult = await browserMod.executeTool(name, input, ctx);
    if (browserResult !== null) return browserResult;
  }

  // maps ツール
  const mapsMod = await getMapsModule();
  if (mapsMod) {
    const mapsResult = await mapsMod.executeTool(name, input, ctx);
    if (mapsResult !== null) return mapsResult;
  }

  // youtube ツール
  const youtubeMod = await getYoutubeModule();
  if (youtubeMod) {
    const youtubeResult = await youtubeMod.executeTool(name, input, ctx);
    if (youtubeResult !== null) return youtubeResult;
  }

  // pieces ツール
  const piecesMod = await getPiecesModule();
  if (piecesMod) {
    const piecesResult = await piecesMod.executeTool(name, input, ctx);
    if (piecesResult !== null) return piecesResult;
  }

  // amazon ツール
  const amazonMod = await getAmazonModule();
  if (amazonMod) {
    const amazonResult = await amazonMod.executeTool(name, input, ctx);
    if (amazonResult !== null) return amazonResult;
  }

  // speech ツール
  const speechMod = await getSpeechModule();
  if (speechMod) {
    const speechResult = await speechMod.executeTool(name, input, ctx);
    if (speechResult !== null) return speechResult;
  }

  // checklist ツール
  const checklistMod = await getChecklistModule();
  if (checklistMod) {
    const checklistResult = await checklistMod.executeTool(name, input, ctx);
    if (checklistResult !== null) return checklistResult;
  }

  // knowledge ツール
  const knowledgeMod = await getKnowledgeModule();
  if (knowledgeMod) {
    const knowledgeResult = await knowledgeMod.executeTool(name, input, ctx);
    if (knowledgeResult !== null) return knowledgeResult;
  }

  // ms-learn ツール
  const msLearnMod = await getMsLearnModule();
  if (msLearnMod) {
    const msLearnResult = await msLearnMod.executeTool(name, input, ctx);
    if (msLearnResult !== null) return msLearnResult;
  }

  // slide ツール (SetTheme / AddSlide / BuildPptx / ResetSlides)
  const slideMod = await getSlideModule();
  if (slideMod) {
    const slideResult = await slideMod.executeTool(name, input, ctx);
    if (slideResult !== null) return slideResult;
  }

  // docs ツール (ReadToolDoc)
  const docsMod = await getDocsModule();
  if (docsMod) {
    const docsResult = await docsMod.executeTool(name, input, ctx);
    if (docsResult !== null) return docsResult;
  }

  // mission ツール (MissionUpdate)
  const missionMod = await getMissionModule();
  if (missionMod) {
    const missionResult = await missionMod.executeTool(name, input, ctx);
    if (missionResult !== null) return missionResult;
  }

  // user-folder ツール (ListUserAssets / RunUserScript)
  const userFolderMod = await getUserFolderModule();
  if (userFolderMod) {
    const userFolderResult = await userFolderMod.executeTool(name, input, ctx);
    if (userFolderResult !== null) return userFolderResult;
  }

  // brainstorm ツール (Brainstorm)
  const brainstormMod = await getBrainstormModule();
  if (brainstormMod) {
    const brainstormResult = await brainstormMod.executeTool(name, input, ctx);
    if (brainstormResult !== null) return brainstormResult;
  }

  // app-docs ツール (ReadAppDoc / ListAppDocs / GetMyOrchestratorState)
  const appDocsMod = await getAppDocsModule();
  if (appDocsMod) {
    const appDocsResult = await appDocsMod.executeTool(name, input, ctx);
    if (appDocsResult !== null) return appDocsResult;
  }

  // ssh ツール (SshExec / SshUpload / SshDownload)
  const sshMod = await getSshModule();
  if (sshMod) {
    const sshResult = await sshMod.executeTool(name, input, ctx);
    if (sshResult !== null) return sshResult;
  }

  // ssh-console ツール (SshConsoleEnsure / Send / Snapshot)
  const sshConsoleMod = await getSshConsoleModule();
  if (sshConsoleMod) {
    const sshConsoleResult = await sshConsoleMod.executeTool(name, input, ctx);
    if (sshConsoleResult !== null) return sshConsoleResult;
  }

  // notes ツール (SearchNotes / ReadNote / WriteNote)
  const notesMod = await getNotesModule();
  if (notesMod) {
    const notesResult = await notesMod.executeTool(name, input, ctx);
    if (notesResult !== null) return notesResult;
  }

  // dashboard ツール (UpdateDashboardWidget)
  const dashboardMod = await getDashboardModule();
  if (dashboardMod) {
    const dashboardResult = await dashboardMod.executeTool(name, input, ctx);
    if (dashboardResult !== null) return dashboardResult;
  }

  // skills ツール (ReadSkill)
  const { executeSkillTool } = await import('./skills.js');
  const skillResult = executeSkillTool(name, input, ctx);
  if (skillResult !== null) return skillResult;

  return { output: `Unknown tool: ${name}`, isError: true };
}

/**
 * ツールを実行するルーター（生データ自動保存ラッパー付き）。
 * executeToolInner に委譲した後、成功した対象ツールの結果を logs/raw/ に保存する。
 */
export async function executeTool(
  name: string,
  input: Record<string, unknown>,
  ctx: ToolContext,
): Promise<ToolResult> {
  logger.debug(`[tools/index] executing ${name}`);

  const result = await executeToolInner(name, input, ctx);

  // raw保存ラッパー: 成功した対象ツールの結果を logs/raw/ に保存
  if (ctx.workspacePath && !result.isError) {
    if (RAW_SAVE_TOOLS.has(name)) {
      saveRawData(ctx.workspacePath, name, result.output);
    } else if (RAW_LOG_ONLY_TOOLS.has(name)) {
      const pathMatch = result.output.match(/-> (.+?) \(/);
      if (pathMatch?.[1]) {
        logRawDownload(ctx.workspacePath, name, pathMatch[1], result.output.length);
      }
    }
    // 構造化データ保存: structuredBlocks があれば logs/structured/ に保存
    if (result.structuredBlocks?.length) {
      saveStructuredBlocks(ctx.workspacePath, result.structuredBlocks);
    }
  }

  return result;
}

// 同期版 getToolDefs のラッパー（後方互換のため、コアツールのみを返す同期版）
export { getCoreToolDefs as getCoreToolDefs };
