import ts from "typescript";

export function findDuplicateTranslationKeys(sourceText, fileName = "generatedTranslations.ts") {
  const source = ts.createSourceFile(
    fileName,
    sourceText,
    ts.ScriptTarget.Latest,
    true,
    ts.ScriptKind.TS
  );
  const findings = [];

  function visit(node) {
    if (
      ts.isVariableDeclaration(node) &&
      ts.isIdentifier(node.name) &&
      node.name.text === "generatedTranslations" &&
      node.initializer &&
      ts.isObjectLiteralExpression(node.initializer)
    ) {
      scanCatalog(node.initializer);
    }
    ts.forEachChild(node, visit);
  }

  function scanCatalog(catalog) {
    for (const localeProperty of catalog.properties) {
      if (!ts.isPropertyAssignment(localeProperty) || !ts.isObjectLiteralExpression(localeProperty.initializer)) {
        continue;
      }
      const locale = propertyName(localeProperty.name);
      const firstDeclarations = new Map();
      for (const translationProperty of localeProperty.initializer.properties) {
        if (!ts.isPropertyAssignment(translationProperty)) continue;
        const key = propertyName(translationProperty.name);
        if (!key) continue;
        const first = firstDeclarations.get(key);
        if (!first) {
          firstDeclarations.set(key, translationProperty.name);
          continue;
        }
        const duplicatePosition = source.getLineAndCharacterOfPosition(
          translationProperty.name.getStart(source)
        );
        const firstPosition = source.getLineAndCharacterOfPosition(first.getStart(source));
        findings.push(
          `${fileName}:${duplicatePosition.line + 1}:${duplicatePosition.character + 1} ` +
          `duplicate generated translation key ${JSON.stringify(key)} in locale ` +
          `${JSON.stringify(locale)}; first declared at line ${firstPosition.line + 1}`
        );
      }
    }
  }

  visit(source);
  return findings;
}

function propertyName(name) {
  if (
    ts.isIdentifier(name) ||
    ts.isStringLiteral(name) ||
    ts.isNumericLiteral(name) ||
    ts.isNoSubstitutionTemplateLiteral(name)
  ) {
    return name.text;
  }
  return "";
}
