/**
 * JsonActionParser 单元测试（TDD）
 * fixtures 来自 Phase 0 PoC 原始报告 + 合成用例
 */
import * as fs from 'node:fs';
import * as path from 'node:path';
import { JsonActionParser } from '../../../../../src/modules/desktop_op/runtime/parser/json_action_parser.js';
import { getParser, registerParser } from '../../../../../src/modules/desktop_op/runtime/parser/registry.js';

const fixturesDir = path.join(__dirname, '../../../../fixtures/desktop_op/vlm_responses');

describe('JsonActionParser fixtures', () => {
  const parser = new JsonActionParser();
  const files = fs.readdirSync(fixturesDir).sort();

  // sanity：至少 20 个 fixture 文件
  it('fixture 文件数量 >= 20', () => {
    expect(files.length).toBeGreaterThanOrEqual(20);
  });

  for (const file of files) {
    it(`解析 fixture: ${file}`, () => {
      const raw = fs.readFileSync(path.join(fixturesDir, file), 'utf-8');
      const action = parser.parseAction(raw);

      if (file.startsWith('success-')) {
        // 成功 fixture 应解析为合法 ActionStep 类型
        expect(['click', 'hotkey', 'type', 'clipboard-write', 'wait', 'mention', 'finished']).toContain(action.type);
      } else if (file.startsWith('failed-')) {
        // 失败 fixture 应返回 failed 类型
        expect(action.type).toBe('failed');
        expect((action as any).reason).toMatch(/parse-error|unknown-type|missing/);
      } else if (file.startsWith('ambiguous-')) {
        // 歧义 fixture 应仍能解析出有效动作（而非 failed）
        expect(action.type).not.toBe('failed');
      }
    });
  }
});

describe('parseVerify', () => {
  const parser = new JsonActionParser();

  it('解析 {"verified":true}', () => {
    expect(parser.parseVerify('{"verified": true}')).toBe(true);
  });

  it('解析 {"verified":false}', () => {
    expect(parser.parseVerify('{"verified": false}')).toBe(false);
  });

  it('解析 markdown 包裹的 verified json', () => {
    expect(parser.parseVerify('```json\n{"verified":true}\n```')).toBe(true);
  });

  it('中文回退："是" -> true', () => {
    expect(parser.parseVerify('是的')).toBe(true);
  });

  it('中文回退："不是" -> false', () => {
    expect(parser.parseVerify('不是')).toBe(false);
  });

  it('垃圾输入返回 false', () => {
    expect(parser.parseVerify('???')).toBe(false);
  });

  it('英文 yes -> true', () => {
    expect(parser.parseVerify('yes, the message is visible')).toBe(true);
  });

  it('英文 no -> false', () => {
    expect(parser.parseVerify('no, the element is not present')).toBe(false);
  });
});

describe('parser registry', () => {
  it('volcengine 返回 JsonActionParser', () => {
    const p = getParser('volcengine');
    expect(p.constructor.name).toBe('JsonActionParser');
  });

  it('未知 provider 返回 JsonActionParser（默认兜底）', () => {
    const p = getParser('unknown-provider');
    expect(p.constructor.name).toBe('JsonActionParser');
  });

  it('registerParser 可覆盖已有条目', () => {
    const fake = new JsonActionParser();
    (fake as any).__marker = 'mock';
    registerParser('volcengine', fake);
    expect((getParser('volcengine') as any).__marker).toBe('mock');
  });
});

describe('buildSystemPrompt', () => {
  it('返回包含 JSON 的中文提示词', () => {
    const parser = new JsonActionParser();
    const dummyTask: any = {
      id: 't1',
      appId: 'weixin',
      target: {},
      actionType: 'send-text',
      params: {},
      enqueuedAt: Date.now(),
    };
    const prompt = parser.buildSystemPrompt(dummyTask);
    expect(prompt).toMatch(/JSON/);
    expect(prompt.length).toBeGreaterThan(20);
  });
});

describe('parseAction 细粒度', () => {
  const parser = new JsonActionParser();

  it('click 缺少 x/y 返回 failed', () => {
    const result = parser.parseAction('{"type":"click"}');
    expect(result.type).toBe('failed');
    expect((result as any).reason).toMatch(/missing/);
  });

  it('hotkey 缺少 key 返回 failed', () => {
    const result = parser.parseAction('{"type":"hotkey"}');
    expect(result.type).toBe('failed');
    expect((result as any).reason).toMatch(/missing/);
  });

  it('type 缺少 text 返回 failed', () => {
    const result = parser.parseAction('{"type":"type"}');
    expect(result.type).toBe('failed');
    expect((result as any).reason).toMatch(/missing/);
  });

  it('wait 缺少 ms 返回 failed', () => {
    const result = parser.parseAction('{"type":"wait"}');
    expect(result.type).toBe('failed');
    expect((result as any).reason).toMatch(/missing/);
  });

  it('unknown type 返回 failed', () => {
    const result = parser.parseAction('{"type":"fly"}');
    expect(result.type).toBe('failed');
    expect((result as any).reason).toMatch(/unknown-type/);
  });

  it('完整 click 解析正确', () => {
    const result = parser.parseAction('{"type":"click","x":100,"y":200}');
    expect(result).toEqual({ type: 'click', x: 100, y: 200 });
  });

  it('click 附带 thought 保留', () => {
    const result = parser.parseAction('{"type":"click","x":10,"y":20,"thought":"点击搜索"}');
    expect(result).toMatchObject({ type: 'click', x: 10, y: 20, thought: '点击搜索' });
  });

  it('finished 无字段合法', () => {
    const result = parser.parseAction('{"type":"finished"}');
    expect(result.type).toBe('finished');
  });

  it('failed 含 reason 合法', () => {
    const result = parser.parseAction('{"type":"failed","reason":"timeout"}');
    expect(result.type).toBe('failed');
    expect((result as any).reason).toBe('timeout');
  });

  it('JSON 嵌套在文本中（bracket scan）', () => {
    const result = parser.parseAction('我决定：{"type":"wait","ms":500} 等待加载完成');
    expect(result).toMatchObject({ type: 'wait', ms: 500 });
  });
});
