import { describe, expect, it } from 'vitest';
import { TOOL_DEFS, executeTool } from './brainstorm.js';
import type { ToolContext } from './core.js';

function makeCtx(): ToolContext {
  return { workspacePath: '/tmp/no-such', editAllowed: false };
}

describe('Brainstorm tool', () => {
  it('exports the Brainstorm tool definition', () => {
    expect(TOOL_DEFS).toHaveProperty('Brainstorm');
    const def = TOOL_DEFS['Brainstorm']!;
    expect(def.function.name).toBe('Brainstorm');
    const params = def.function.parameters as { required?: string[] };
    expect(params.required).toEqual(expect.arrayContaining(['task', 'approaches', 'chosen', 'rationale']));
  });

  it('returns null for other tool names (dispatch isolation)', async () => {
    const result = await executeTool('SomethingElse', {}, makeCtx());
    expect(result).toBeNull();
  });

  it('requires task field', async () => {
    const result = await executeTool('Brainstorm', { approaches: [{ name: 'a', description: 'x' }, { name: 'b', description: 'y' }], chosen: 'a', rationale: 'r' }, makeCtx());
    expect(result?.isError).toBe(true);
    expect(result?.output).toContain('task');
  });

  it('rejects single approach (needs 2+ for comparison)', async () => {
    const result = await executeTool('Brainstorm', {
      task: 't',
      approaches: [{ name: 'only', description: 'one' }],
      chosen: 'only',
      rationale: 'r',
    }, makeCtx());
    expect(result?.isError).toBe(true);
    expect(result?.output).toContain('2 個以上');
  });

  it('rejects when chosen does not match any approach name', async () => {
    const result = await executeTool('Brainstorm', {
      task: 't',
      approaches: [{ name: 'a', description: 'x' }, { name: 'b', description: 'y' }],
      chosen: 'nonexistent',
      rationale: 'r',
    }, makeCtx());
    expect(result?.isError).toBe(true);
    expect(result?.output).toContain('一致しません');
  });

  it('formats the approaches and marks the chosen one', async () => {
    const result = await executeTool('Brainstorm', {
      task: 'input/data.xlsx の中身を要約したい',
      approaches: [
        { name: 'ReadExcel 直接', description: 'ReadExcel で読む', reliability: 'high', speed: 'fast' },
        { name: 'CSV エクスポート経由', description: 'CSV に変換してから Read', reliability: 'medium', speed: 'medium' },
        { name: 'ファイル拡張子確認後判断', description: 'Bash file で本体形式を確認', reliability: 'high', speed: 'slow' },
      ],
      chosen: 'ReadExcel 直接',
      rationale: '通常はこれが最速で確実',
    }, makeCtx());

    expect(result?.isError).toBe(false);
    expect(result?.output).toContain('# Brainstorm: input/data.xlsx');
    expect(result?.output).toContain('検討した 3 個のアプローチ');
    expect(result?.output).toMatch(/✓\s+\*\*ReadExcel 直接\*\*/);
    expect(result?.output).toContain('採用: ReadExcel 直接');
    expect(result?.output).toContain('通常はこれが最速で確実');
    expect(result?.output).toContain('確実性: high');
  });

  it('preserves optional context field for stuck-recovery use case', async () => {
    const result = await executeTool('Brainstorm', {
      task: 'output/foo.xlsx を読みたい',
      context: 'ReadExcel が JSZip エラー、ReadPdf も拡張子 mismatch で reject 済み',
      approaches: [
        { name: 'Glob で実在確認', description: 'Glob output/* で実際のファイル一覧を取る' },
        { name: 'ユーザーに ASK', description: '正しいパスを確認' },
      ],
      chosen: 'Glob で実在確認',
      rationale: '能動的に状況を取りに行ける',
    }, makeCtx());

    expect(result?.isError).toBe(false);
    expect(result?.output).toContain('背景 / これまでの試行');
    expect(result?.output).toContain('JSZip エラー');
  });
});
