import { describe, expect, it } from "vitest";
import {
  CODE_MODE_SHELL_SOURCE_ERROR,
  isShellLikeCodeModeSource,
} from "./code-mode-shell-source.js";

describe("isShellLikeCodeModeSource", () => {
  it.each([
    "ls",
    "ls -1",
    "ls -la /workspace/",
    "ls -la /workspace",
    "ls /var/log",
    "pwd",
    "pwd;",
    "pwd; // inspect the workspace",
    "# inspect the workspace\npwd",
    "# inspect the workspace\n# then report it\npwd",
    "#!/bin/sh\npwd",
    "#!/usr/bin/env bash\nset -euo pipefail\npwd",
    "pwd\nls -la /workspace",
    "pwd;ls -la /workspace",
    "pwd && ls /workspace",
    "pwd||ls /workspace",
    "echo hello",
    "cat /workspace/HEARTBEAT.md",
    "find /workspace -maxdepth 1 -type f | head -50",
    "echo listing; ls /workspace/ 2>&1 || echo failed",
    "ls /workspace/ > /tmp/wlist.txt 2>&1; cat /tmp/wlist.txt",
    "/bin/ls /workspace/",
    "/usr/bin/find /workspace",
    "/usr/local/bin/python3 script.py",
    "sh -c 'ls /workspace/'",
    "bash -lc 'pwd'",
    "export FOO=bar",
    "export PATH=/workspace/bin",
    "env FOO=bar node script.js",
    "NODE_ENV=test npm test",
    "NODE_ENV=test\nnpm test",
    "FOO=bar\r\n  npm test",
    "FOO=bar ./gradlew test",
    "FOO=bar BAR=baz node --version",
    'GREETING="hello world" npm test',
    "GREETING='hello world' ./gradlew test",
    "EMPTY= npm test",
    "// inspect the workspace\npwd",
    "/* inspect the workspace */ pwd;",
    "// use a clean environment\nNODE_ENV=test npm test",
    "git status",
    'git status; const note = "git";',
    'git status; const note = "function git";',
    "ls -1; const metadata = { ls: true };",
    "ls -1; const note = 'function ls';",
    "ls -1; let ls = 7;",
    "pwd; class/**/pwd {}",
    "npm test",
    "npx vitest run",
    "pnpm test src/agents/code-mode.test.ts",
    "rg code-mode src/agents",
    "sudo ls /workspace",
    "docker ps",
    "kubectl get pods",
    "make test",
    "set -euo pipefail",
    "exit",
    "logout",
    "if [ -d /workspace ]; then pwd; fi",
    "if [[ -d /workspace ]]; then pwd; fi",
    "while test -d /workspace; do pwd; done",
    'for file in /workspace/*; do echo "$file"; done',
    'for ((i=0; i<3; i++)); do echo "$i"; done',
    "function task { pwd; }",
    "source ./env",
    "command ls",
    "whoami",
    "date",
    "uname -a",
    "go test ./...",
    "cargo test",
    "sort /workspace/file",
    "wc -l file",
    "jq . file.json",
    "exec ls",
    "cut -d : file",
    "uniq -c file",
    "custom-tool --format=json",
    "some_cli /workspace/file",
    "ls > output",
    "ls>output",
    "ls >output",
    "ls >> output",
    "ls>>output",
    "ls 2> error",
    "ls < input",
    "cat<input",
    "cat <input",
    "python3 script.py",
    "node script.js",
    "powershell -Command Get-Location",
    "pwsh -Command Get-Location",
    "./script.sh --verbose",
    "./gradlew test",
    ".\\gradlew.bat test",
    ".\\script.ps1",
    "C:\\workspace\\run.cmd /q",
    "C:\\workspace\\script.ps1 -Verbose",
    "./configure --prefix=/workspace",
    "../bin/task --verbose",
    "../scripts/run.bash",
    "/workspace/run.sh --verbose",
    "/opt/homebrew/bin/tool --version",
    "~/bin/task",
    "~/scripts/run.zsh",
    "  ls -la /workspace/  ",
  ])("rejects the shell command %j", (source) => {
    expect(isShellLikeCodeModeSource(source)).toBe(true);
  });

  it.each([
    "",
    "  ",
    "true",
    "true;",
    "false",
    "false;",
    "null;",
    "42;",
    '"ls /workspace";',
    "return 7;",
    "return -1;",
    "return /foo/.test('foo');",
    "return true || false;",
    "Infinity -1; return 42;",
    "eval; return typeof eval;",
    "Date -1; return 7;",
    "if (true) { return -1; }",
    "while (false) { return 7; }",
    "for (let i = 0; i < 3; i++) { if (i === 2) { return i; } }",
    "function task() { return 7; } return task();",
    "const value = ;",
    "let value = ;",
    "value || fallback",
    "value && fallback",
    "value | mask",
    "value > limit",
    "/workspace/.test(value)",
    "/foo/.test('foo')",
    "ls('workspace')",
    "ls .call(null)",
    "ls ?.('workspace')",
    "ls = 7",
    "ls + count",
    "ls - count",
    "ls -1; function ls() {}",
    "ls -1; function/**/ls() {}",
    "ls -la /workspace; function ls() {}",
    "echo('hello')",
    "echo `hello`; function echo(parts) { return parts[0]; }",
    "pwd?.()",
    "pwd; function pwd() {}",
    "pwd\nfunction pwd() {}",
    "pwd; var { pwd } = { pwd: 7 }; return pwd;",
    "pwd; var [pwd] = [7]; return pwd;",
    "pwd; var { nested: { pwd } } = { nested: { pwd: 7 } }; return pwd;",
    "pwd; for (var pwd of [7]) {} return pwd;",
    "pwd; var other = 1, pwd = 7; return pwd;",
    "pwd; function* pwd() { yield 7; }",
    "pwd; function/**/pwd() {}",
    "pwd; function/**/\u002a/**/pwd() { yield 7; }",
    "pwd; var/**/{ pwd } = { pwd: 7 }; return pwd;",
    "node -version; function/**/node() {}; var version = 1;",
    "ls > limit; function ls() {} var limit = 1;",
    "test instanceof Function; function test() {}",
    "git instanceof Function; function git() {}",
    "export const answer = 7;",
    "export abstract class Example {}",
    "export import Alias = require('./module');",
    "export declare namespace Example {}",
    "export as namespace Example;",
    "export = Example;",
    "export async function read() {}",
    "export { answer };",
    "export * from './types';",
    "export interface Result { value: number }",
    "export enum Color { Red, Green }",
    'const result = await tools.callValue("openclaw:core:exec", { command: "ls" }); return result;',
    'return await tools.callValue("openclaw:core:read", { path: "/workspace" });',
    "console.log(await tools.callValue('openclaw:core:read', { path: '/workspace' }));",
    "// shell documentation: ls /workspace\nreturn 7;",
    "// shell documentation: ls /workspace\nconst answer = 7; return answer;",
    "/* typed module */ export interface Result { value: number }",
  ])("preserves the JavaScript or TypeScript source %j", (source) => {
    expect(isShellLikeCodeModeSource(source)).toBe(false);
  });

  it.each([
    {
      source: "node -1; var node: number = 7;",
      preparedSource: "node -1; var node = 7;",
    },
    {
      source: "node --version; var node: number = 2, version = 1;",
      preparedSource: "node--; version; var node = 2, version = 1;",
    },
  ])("preserves transpiled command-like TypeScript: $source", ({ source, preparedSource }) => {
    expect(isShellLikeCodeModeSource(source, preparedSource)).toBe(false);
  });

  it("explains how to execute a real catalog tool without retrying shell source", () => {
    expect(CODE_MODE_SHELL_SOURCE_ERROR).toContain("JavaScript or TypeScript");
    expect(CODE_MODE_SHELL_SOURCE_ERROR).toContain("not shell");
    expect(CODE_MODE_SHELL_SOURCE_ERROR).toContain("tools.callValue");
    expect(CODE_MODE_SHELL_SOURCE_ERROR).toContain("ALL_TOOLS");
    expect(CODE_MODE_SHELL_SOURCE_ERROR).toContain("Do not retry");
  });
});
