import { describe, it, expect } from 'vitest';
import { executeTool } from './mission.js';
import type { MissionBriefIO, MissionBriefValue, ToolContext } from './core.js';

function makeIO(initial: MissionBriefValue | null = null) {
  let state: MissionBriefValue | null = initial ? { ...initial } : null;
  const io: MissionBriefIO = {
    read: () => (state ? { ...state } : null),
    update: (patch) => {
      const next: MissionBriefValue = {
        goal: patch.goal !== undefined ? patch.goal : state?.goal ?? '',
        done: patch.done !== undefined ? patch.done : state?.done ?? '',
        open: patch.open !== undefined ? patch.open : state?.open ?? '',
        clarifications: patch.clarifications !== undefined ? patch.clarifications : state?.clarifications ?? '',
      };
      const allEmpty = !next.goal && !next.done && !next.open && !next.clarifications;
      state = allEmpty ? null : next;
      return state ? { ...state } : null;
    },
  };
  return { io, get: () => state };
}

function makeCtx(io?: MissionBriefIO): ToolContext {
  return {
    workspacePath: '/tmp/dummy',
    editAllowed: false,
    missionBrief: io,
  };
}

describe('mission_update tool', () => {
  it('writes the provided fields and returns merged result text', async () => {
    const { io, get } = makeIO();
    const result = await executeTool('MissionUpdate', { goal: 'ship', done: '- a' }, makeCtx(io));
    expect(result?.isError).toBe(false);
    expect(result?.output).toContain('Mission Brief を更新しました');
    expect(get()?.goal).toBe('ship');
    expect(get()?.done).toBe('- a');
    expect(get()?.open).toBe('');
  });

  it('partial replace: undefined fields leave prior values intact', async () => {
    const { io, get } = makeIO({ goal: 'A', done: 'B', open: 'C', clarifications: 'D' });
    await executeTool('MissionUpdate', { done: 'B-2' }, makeCtx(io));
    expect(get()?.goal).toBe('A');
    expect(get()?.done).toBe('B-2');
    expect(get()?.open).toBe('C');
    expect(get()?.clarifications).toBe('D');
  });

  it('errors when no fields are provided', async () => {
    const { io } = makeIO();
    const result = await executeTool('MissionUpdate', {}, makeCtx(io));
    expect(result?.isError).toBe(true);
    expect(result?.output).toContain('更新するフィールドが1つも指定');
  });

  it('errors when missionBrief IO is unavailable (subtask context)', async () => {
    const result = await executeTool('MissionUpdate', { goal: 'x' }, makeCtx(undefined));
    expect(result?.isError).toBe(true);
    expect(result?.output).toContain('利用できません');
  });

  it('returns null for unknown tool name (router pass-through)', async () => {
    const { io } = makeIO();
    const result = await executeTool('SomethingElse', {}, makeCtx(io));
    expect(result).toBeNull();
  });

  it('truncates oversized field values to keep the row reasonable', async () => {
    const { io, get } = makeIO();
    const huge = 'X'.repeat(5_000);
    await executeTool('MissionUpdate', { goal: huge }, makeCtx(io));
    const stored = get()?.goal ?? '';
    expect(stored.length).toBeLessThan(huge.length);
    expect(stored).toContain('truncated');
  });
});
