import { cleanCodeToolOutput } from './cleanup';

/**
 * Real bash_tool outputs captured from a deployed conversation. Patterns
 * tested live: trailing single `Note:` paragraph, double trailing
 * `Note:` paragraphs, per-file `| <annotation>` suffixes (downloaded /
 * displayed / known-as-input), and inline-comma file lists.
 */
describe('cleanCodeToolOutput', () => {
  it('returns empty/falsy input unchanged', () => {
    expect(cleanCodeToolOutput('')).toBe('');
  });

  it('strips a trailing single `Note:` paragraph (mkdir-only output)', () => {
    const input = [
      'stdout:',
      'Folder created successfully!',
      '',
      'Generated files:',
      '- /mnt/data/test_folder/.dirkeep',
      '',
      '',
      'Note: Files from previous executions are automatically available and can be modified.',
    ].join('\n');
    const output = cleanCodeToolOutput(input);
    expect(output).not.toMatch(/Note:/);
    expect(output).toMatch(/Folder created successfully!/);
    expect(output).toMatch(/Generated files:/);
    expect(output).toMatch(/- \/mnt\/data\/test_folder\/\.dirkeep$/);
  });

  it('strips both trailing `Note:` paragraphs when two are emitted', () => {
    const input = [
      'stdout:',
      'File created successfully!',
      '',
      'Generated files:',
      '- /mnt/data/test_folder/test_file.txt',
      'Available files (inputs, not generated by this execution):',
      '- /mnt/data/test_folder/.dirkeep',
      '',
      '',
      'Note: Files from previous executions are automatically available and can be modified.',
      '',
      'Note: Files in "Available files" are inputs the user (or a skill) already provided to the sandbox. They were not produced by this execution and you should not present them as new outputs in your response.',
    ].join('\n');
    const output = cleanCodeToolOutput(input);
    expect(output).not.toMatch(/Note:/);
    expect(output).toMatch(/Generated files:/);
    expect(output).toMatch(/Available files \(inputs/);
  });

  it('strips per-file "downloaded" / "known to the user" / "displayed" annotations', () => {
    const input = [
      'Generated files:',
      '- /mnt/data/a.txt | File is already downloaded by the user',
      '- /mnt/data/b.png | Image is already displayed to the user',
      'Available files (inputs, not generated by this execution):',
      '- /mnt/data/c.txt | Available as an input — already known to the user',
    ].join('\n');
    const output = cleanCodeToolOutput(input);
    expect(output).not.toMatch(/already downloaded/);
    expect(output).not.toMatch(/already displayed/);
    expect(output).not.toMatch(/already known to the user/);
    expect(output).toMatch(/- \/mnt\/data\/a\.txt$/m);
    expect(output).toMatch(/- \/mnt\/data\/b\.png$/m);
    expect(output).toMatch(/- \/mnt\/data\/c\.txt$/m);
  });

  it('handles inline comma-separated file lists (small file count formatting)', () => {
    // The bash executor inlines the list with `, ` when ≤ 3 files.
    const input =
      'Available files (inputs, not generated by this execution):\n- /mnt/data/test_folder/test_file.txt | Available as an input — already known to the user, - /mnt/data/test_folder/.dirkeep | Available as an input — already known to the user';
    const output = cleanCodeToolOutput(input);
    expect(output).not.toMatch(/already known to the user/);
    expect(output).toMatch(/- \/mnt\/data\/test_folder\/test_file\.txt/);
    expect(output).toMatch(/- \/mnt\/data\/test_folder\/\.dirkeep/);
  });

  it('passes through output that contains no boilerplate (no false positives)', () => {
    const input = 'stdout:\nHello, world!\n';
    expect(cleanCodeToolOutput(input)).toBe('stdout:\nHello, world!');
  });

  it('does not strip the word "Note:" mid-output (only trailing paragraphs)', () => {
    // A user-authored echo `Note: this is real content` mid-output should
    // not be eaten by the trailing-Notes regex; only paragraphs that
    // start with `Note:` AFTER a blank line near end-of-string are matched.
    const input = [
      'stdout:',
      'Note: this is real content',
      'more output',
      '',
      'Generated files:',
      '- /mnt/data/foo.txt',
    ].join('\n');
    const output = cleanCodeToolOutput(input);
    expect(output).toMatch(/Note: this is real content/);
  });

  it('preserves a user-authored "Note:" line that follows a blank line in stdout', () => {
    /** Tightened anchor: the trailing-notes regex now requires one of the
     * known boilerplate openings (`Files from previous executions`, etc.)
     * after `Note:`. A user `print()` that happens to output a blank
     * line followed by `Note: ...something else...` must survive
     * untouched, along with everything that follows it. */
    const input = [
      'stdout:',
      'first line',
      '',
      "Note: this is the user's measurement output",
      'more output',
      '',
      'Generated files:',
      '- /mnt/data/foo.txt',
    ].join('\n');
    const output = cleanCodeToolOutput(input);
    expect(output).toMatch(/Note: this is the user's measurement output/);
    expect(output).toMatch(/Generated files:/);
    expect(output).toMatch(/- \/mnt\/data\/foo\.txt$/);
  });

  it('drops trailing blank lines after stripping', () => {
    const input =
      'stdout:\nresult\n\n\nNote: Files from previous executions are automatically available and can be modified.';
    expect(cleanCodeToolOutput(input)).toBe('stdout:\nresult');
  });

  it('does NOT mutate stdout that legitimately contains an annotation phrase outside a file-list section', () => {
    /** Codex regression: the previous global `.replace` would strip
     * any line ending in one of the three annotation phrases — even
     * if that line was the user's own stdout. A script doing
     * `echo "foo | File is already downloaded by the user"` had its
     * output silently mangled before being fed back into model
     * context. With section-scoped stripping, the script's stdout
     * passes through unchanged because there's no `Generated files:`
     * or `Available files (...)` header above it. */
    const input = [
      'stdout:',
      'foo | File is already downloaded by the user',
      'bar | Image is already displayed to the user',
      'baz | Available as an input — already known to the user',
    ].join('\n');
    const output = cleanCodeToolOutput(input);
    expect(output).toMatch(/foo \| File is already downloaded by the user/);
    expect(output).toMatch(/bar \| Image is already displayed to the user/);
    expect(output).toMatch(/baz \| Available as an input — already known to the user/);
  });

  it('strips annotations inside a file-list section but preserves identical phrases in stdout above it', () => {
    /** Mixed case: the same execution's stdout coincidentally echoes
     * one of the annotation phrases AND a file gets generated. The
     * stdout phrase must survive; the file-listing annotation must
     * still get stripped. */
    const input = [
      'stdout:',
      'echo output: foo | File is already downloaded by the user',
      '',
      'Generated files:',
      '- /mnt/data/foo.txt | File is already downloaded by the user',
    ].join('\n');
    const output = cleanCodeToolOutput(input);
    // Stdout line preserved verbatim.
    expect(output).toMatch(/echo output: foo \| File is already downloaded by the user/);
    // File-listing line had its annotation stripped.
    expect(output).toMatch(/- \/mnt\/data\/foo\.txt$/m);
    // The annotation phrase appears EXACTLY once now (only in stdout,
    // not on the file-listing line).
    const phraseCount = (output.match(/File is already downloaded by the user/g) ?? []).length;
    expect(phraseCount).toBe(1);
  });
});
