#!/usr/bin/env node

import ts from "typescript";
import { createPairingGuardContext } from "./lib/pairing-guard-context.mjs";
import {
  collectFileViolations,
  getPropertyNameText,
  runAsScript,
  toLine,
} from "./lib/ts-guard-utils.mjs";

const { repoRoot, sourceRoots } = createPairingGuardContext(import.meta.url);

function isUndefinedLikeExpression(node) {
  if (ts.isIdentifier(node) && node.text === "undefined") {
    return true;
  }
  return node.kind === ts.SyntaxKind.NullKeyword;
}

function hasRequiredAccountIdProperty(node) {
  if (!ts.isObjectLiteralExpression(node)) {
    return false;
  }
  for (const property of node.properties) {
    if (ts.isShorthandPropertyAssignment(property) && property.name.text === "accountId") {
      return true;
    }
    if (!ts.isPropertyAssignment(property)) {
      continue;
    }
    if (getPropertyNameText(property.name) !== "accountId") {
      continue;
    }
    if (isUndefinedLikeExpression(property.initializer)) {
      return false;
    }
    return true;
  }
  return false;
}

function findViolations(content, filePath) {
  const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true);
  const violations = [];

  const visit = (node) => {
    if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
      const callName = node.expression.text;
      if (callName === "readChannelAllowFromStore") {
        if (node.arguments.length < 3 || isUndefinedLikeExpression(node.arguments[2])) {
          violations.push({
            line: toLine(sourceFile, node),
            reason: "readChannelAllowFromStore call must pass explicit accountId as 3rd arg",
          });
        }
      } else if (
        callName === "readLegacyChannelAllowFromStore" ||
        callName === "readLegacyChannelAllowFromStoreSync"
      ) {
        violations.push({
          line: toLine(sourceFile, node),
          reason: `${callName} is legacy-only; use account-scoped readChannelAllowFromStore* APIs`,
        });
      } else if (callName === "upsertChannelPairingRequest") {
        const firstArg = node.arguments[0];
        if (!firstArg || !hasRequiredAccountIdProperty(firstArg)) {
          violations.push({
            line: toLine(sourceFile, node),
            reason: "upsertChannelPairingRequest call must include accountId in params",
          });
        }
      }
    }
    ts.forEachChild(node, visit);
  };

  visit(sourceFile);
  return violations;
}

async function main() {
  const violations = await collectFileViolations({
    sourceRoots,
    repoRoot,
    findViolations,
  });

  if (violations.length === 0) {
    return;
  }

  console.error("Found unscoped pairing-store calls:");
  for (const violation of violations) {
    console.error(`- ${violation.path}:${violation.line} (${violation.reason})`);
  }
  process.exit(1);
}

runAsScript(import.meta.url, main);
