/**
 * Mission Brief tool — per-task pinned memo of goal / done / open /
 * clarifications, always rendered at the top of every movement's system
 * prompt and editable by both the LLM (via this tool) and the user
 * (via the Overview tab).
 *
 * Design notes:
 *   - Partial replace semantics: only fields explicitly provided in the
 *     call are written. Undefined fields leave existing values intact.
 *   - The brief is per-LocalTask (not per-job, not per-movement) so it
 *     survives across iterations, ASK rounds, and follow-up messages
 *     within the same task conversation.
 *   - Storage is a single JSON column on local_tasks; see
 *     src/db/repository.ts.MissionBrief / updateMissionBrief.
 *   - Plumbing: piece-runner constructs a MissionBriefIO from the
 *     localTaskId + repo and threads it through ToolContext.
 *     Subtask contexts that aren't bound to a local_task simply leave
 *     the IO unset; the tool then degrades to a no-op with a clear
 *     error so the LLM doesn't get confused.
 */

import { ToolDef } from '../../llm/openai-compat.js';
import type { ToolContext, ToolResult } from './core.js';
import { MISSION_BRIEF_FIELDS, type MissionBriefField } from '../../db/repository.js';

// Per-field 1-line descriptions, iterated to build the tool params so a new
// field is a one-line addition (matching MISSION_BRIEF_FIELDS in repository.ts).
const FIELD_DESCRIPTIONS: Record<MissionBriefField, string> = {
  goal: 'このタスク全体のゴール (ユーザーが最初に依頼した本質的な要件)。Markdown 可。',
  done: 'これまでに完了した主要マイルストーン。Markdown 箇条書き推奨。重複作業を避けるための参照。',
  open: '残っている作業 / 未解決のブロッカー。Markdown 箇条書き推奨。',
  clarifications: 'ユーザーから途中で追加された補足・制約。「これは壊さないで」など。Markdown 可。',
  user_constraints: 'ユーザーが明示した恒久的な制約 (「X は変えないで」「認証フローは維持」等)。可能なら comment:N / transcript:N を出典として添える。',
  decisions: '検討の末に確定した設計判断とその理由。後で蒸し返さないための記録。',
  current_focus: 'いま取り組んでいる作業の焦点。movement をまたいで現在地を見失わないため。',
};

const MISSION_UPDATE_DEF: ToolDef = {
  type: 'function',
  function: {
    name: 'MissionUpdate',
    description:
      'タスクの Mission Brief (goal / done / open / clarifications / user_constraints / decisions / current_focus) を更新する。常時利用可能で META_TOOL 扱い。**新規タスクの最初のツール呼び出しで goal を必ず set すること** ── ユーザー要件を verbatim に固定し、会話が長くなった後でも参照点として残す。以降は節目で done / open / current_focus を更新し、恒久的な制約・判断は user_constraints / decisions に pin する。指定したフィールドだけ置き換わり、未指定は変更なし。詳細は ReadToolDoc({ name: "MissionUpdate" })。',
    parameters: {
      type: 'object',
      properties: Object.fromEntries(
        MISSION_BRIEF_FIELDS.map((field) => [field, { type: 'string', description: FIELD_DESCRIPTIONS[field] }]),
      ),
    },
  },
};

export const TOOL_DEFS: Record<string, ToolDef> = {
  MissionUpdate: MISSION_UPDATE_DEF,
};

const FIELD_MAX_CHARS = 2000;

function clamp(value: unknown): string | undefined {
  if (value === undefined) return undefined;
  if (typeof value !== 'string') return undefined;
  if (value.length <= FIELD_MAX_CHARS) return value;
  return `${value.slice(0, FIELD_MAX_CHARS)}\n…[truncated, ${value.length} chars]`;
}

export async function executeTool(
  name: string,
  input: Record<string, unknown>,
  ctx: ToolContext,
): Promise<ToolResult | null> {
  if (name !== 'MissionUpdate') return null;

  const io = ctx.missionBrief;
  if (!io) {
    return {
      output: 'MissionUpdate はこのコンテキストでは利用できません (subtask など local_task と紐付かない実行)。',
      isError: true,
    };
  }

  // Only fields explicitly provided are written; undefined leaves existing
  // values intact (partial-replace). Iterate the shared field list so a new
  // field needs no change here.
  const filtered: Partial<Record<MissionBriefField, string>> = {};
  for (const key of MISSION_BRIEF_FIELDS) {
    const clamped = clamp(input[key]);
    if (clamped !== undefined) filtered[key] = clamped;
  }

  if (Object.keys(filtered).length === 0) {
    return {
      output: `更新するフィールドが1つも指定されませんでした。${MISSION_BRIEF_FIELDS.join(' / ')} のいずれかを指定してください。`,
      isError: true,
    };
  }

  try {
    const merged = io.update(filtered);
    if (!merged) {
      return {
        output: 'Mission Brief をクリアしました (全フィールドが空)。',
        isError: false,
      };
    }
    const summary = ['Mission Brief を更新しました:'];
    for (const key of MISSION_BRIEF_FIELDS) {
      const value = merged[key];
      if (value) summary.push(`- ${key} (${value.length} chars)`);
    }
    return { output: summary.join('\n'), isError: false };
  } catch (err) {
    return {
      output: `Mission Brief の更新に失敗しました: ${err instanceof Error ? err.message : String(err)}`,
      isError: true,
    };
  }
}
