import { readFileSync } from "node:fs";
import ts from "typescript";
import { describe, expect, it } from "vitest";

const MOJIBAKE = /闂\?|濠电姷|鏁告|鈥|�/u;

function userVisibleLiteralIssues(file: string): string[] {
  const source = readFileSync(file, "utf8");
  const sf = ts.createSourceFile(file, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
  const issues: string[] = [];

  function check(node: ts.Node, text: string): void {
    if (!MOJIBAKE.test(text)) return;
    const pos = sf.getLineAndCharacterOfPosition(node.getStart(sf));
    issues.push(`${file}:${pos.line + 1}:${pos.character + 1} ${JSON.stringify(text)}`);
  }

  function visit(node: ts.Node): void {
    if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
      check(node, node.text);
    } else if (
      node.kind === ts.SyntaxKind.TemplateHead ||
      node.kind === ts.SyntaxKind.TemplateMiddle ||
      node.kind === ts.SyntaxKind.TemplateTail
    ) {
      check(node, (node as ts.TemplateLiteralLikeNode).text);
    } else if (ts.isJsxText(node)) {
      check(node, node.getText(sf));
    }
    ts.forEachChild(node, visit);
  }

  visit(sf);
  return issues;
}

describe("App user-visible strings", () => {
  it("does not contain mojibake in runtime string literals", () => {
    expect(userVisibleLiteralIssues("src/cli/ui/App.tsx")).toEqual([]);
  });
});