#!/usr/bin/env node

import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const SERVICE_ROOT = path.resolve(__dirname, '..');
const REPO_ROOT = path.resolve(SERVICE_ROOT, '../..');
const DIST_ROOT = path.resolve(
  process.env.WORKFLOW_WORKER_VALIDATE_DIST_ROOT || path.join(SERVICE_ROOT, 'dist'),
);

const ENTRY_CANDIDATES = [
  path.join(DIST_ROOT, 'services/workflow-worker/src/index.js'),
  path.join(DIST_ROOT, 'src/index.js'),
];

const EXTRA_ENTRY_CANDIDATES = [
  // The worker imports @alga-psa/workflows/runtime/worker as a package export.
  // That package dist is outside services/workflow-worker/dist, so scan it
  // explicitly to catch bundled alias/server/UI leaks before Docker runtime.
  path.join(REPO_ROOT, 'ee/packages/workflows/dist/runtime/worker.mjs'),
  path.join(REPO_ROOT, 'ee/packages/workflows/dist/runtime/core.mjs'),
];

const FORBIDDEN_ROOT_IMPORTS = new Set([
  '@alga-psa/auth',
  '@alga-psa/documents',
  '@alga-psa/integrations',
  '@alga-psa/billing',
  '@alga-psa/ui',
]);

function readFile(filePath) {
  return fs.readFileSync(filePath, 'utf8');
}

function findEntry() {
  for (const candidate of ENTRY_CANDIDATES) {
    if (fs.existsSync(candidate)) {
      return candidate;
    }
  }
  return null;
}

function extractSpecifiers(source) {
  const specs = [];

  const staticImportRe = /(?:import|export)\s+(?:[^'"]*?\sfrom\s*)?['"]([^'"]+)['"]/g;
  const dynamicImportRe = /import\(\s*['"]([^'"]+)['"]\s*\)/g;

  for (const re of [staticImportRe, dynamicImportRe]) {
    let match;
    while ((match = re.exec(source)) !== null) {
      specs.push(match[1]);
    }
  }

  return specs;
}

function resolveRelativeImport(fromFile, specifier) {
  const fromDir = path.dirname(fromFile);
  const rawPath = path.resolve(fromDir, specifier);
  if (fs.existsSync(rawPath) && fs.statSync(rawPath).isFile()) {
    return rawPath;
  }

  const candidates = [
    `${rawPath}.js`,
    `${rawPath}.mjs`,
    `${rawPath}.cjs`,
    `${rawPath}.json`,
    path.join(rawPath, 'index.js'),
    path.join(rawPath, 'index.mjs'),
    path.join(rawPath, 'index.cjs'),
  ];
  return candidates.find((candidate) => fs.existsSync(candidate)) ?? null;
}

function isRelative(specifier) {
  return specifier.startsWith('./') || specifier.startsWith('../');
}

function isPathWithin(basePath, candidatePath) {
  const rel = path.relative(basePath, candidatePath);
  return rel && !rel.startsWith('..') && !path.isAbsolute(rel);
}

function addViolation(violations, filePath, specifier, reason) {
  violations.push({
    filePath: path.relative(SERVICE_ROOT, filePath),
    specifier,
    reason,
  });
}

function isWorkerRuntimeEntrypoint(filePath) {
  return filePath.endsWith(path.join('ee', 'packages', 'workflows', 'src', 'runtime', 'worker.js'));
}

function validate() {
  if (!fs.existsSync(DIST_ROOT)) {
    throw new Error(`dist not found at ${DIST_ROOT}`);
  }

  const entry = findEntry();
  if (!entry) {
    throw new Error('Unable to locate workflow-worker dist entrypoint');
  }

  const queue = [
    entry,
    ...EXTRA_ENTRY_CANDIDATES.filter((candidate) => fs.existsSync(candidate)),
  ];
  const visited = new Set();
  const violations = [];

  while (queue.length > 0) {
    const current = queue.shift();
    if (!current || visited.has(current)) continue;
    visited.add(current);

    const source = readFile(current);
    const specifiers = extractSpecifiers(source);

    for (const specifier of specifiers) {
      if (FORBIDDEN_ROOT_IMPORTS.has(specifier)) {
        addViolation(
          violations,
          current,
          specifier,
          'forbidden package root import in worker runtime graph'
        );
      }

      if (specifier.startsWith('@alga-psa/ui/')) {
        addViolation(
          violations,
          current,
          specifier,
          'ui package import is not allowed in worker runtime graph'
        );
      }

      if (specifier.startsWith('@shared/')) {
        addViolation(
          violations,
          current,
          specifier,
          'unresolved @shared alias is not allowed in worker runtime graph'
        );
      }

      if (specifier.includes('/runtime/bootstrap')) {
        addViolation(
          violations,
          current,
          specifier,
          'bootstrap/app-only runtime dependency leaked into worker runtime graph'
        );
      }

      if (
        (specifier.includes('workflowInferenceService') || specifier.includes('registerAiActions'))
        && !isWorkerRuntimeEntrypoint(current)
      ) {
        addViolation(
          violations,
          current,
          specifier,
          'worker runtime graph may only reach AI runtime wiring through the dedicated runtime/worker entrypoint'
        );
      }

      if (
        specifier.includes('/components/') ||
        specifier.endsWith('/components')
      ) {
        addViolation(
          violations,
          current,
          specifier,
          'component import leaked into worker runtime graph'
        );
      }

      if (!isRelative(specifier)) {
        continue;
      }

      const ext = path.extname(specifier);
      if (!ext) {
        addViolation(
          violations,
          current,
          specifier,
          'relative import is missing explicit extension'
        );
      } else if (ext === '.jsx') {
        addViolation(
          violations,
          current,
          specifier,
          'relative .jsx import is not allowed for Node worker runtime'
        );
      }

      const resolved = resolveRelativeImport(current, specifier);
      if (!resolved) {
        addViolation(
          violations,
          current,
          specifier,
          'relative import does not resolve in dist output'
        );
        continue;
      }

      if (resolved.endsWith('.jsx')) {
        addViolation(
          violations,
          current,
          specifier,
          'resolved path is .jsx, which is not executable by Node runtime here'
        );
      }

      if (isPathWithin(DIST_ROOT, resolved)) {
        queue.push(resolved);
      }
    }
  }

  if (violations.length > 0) {
    console.error('\nWorkflow worker runtime import validation failed.\n');
    for (const violation of violations) {
      console.error(`- ${violation.filePath} -> "${violation.specifier}"`);
      console.error(`  ${violation.reason}`);
    }
    process.exit(1);
  }

  console.log('Workflow worker runtime import validation passed.');
}

try {
  validate();
} catch (error) {
  console.error('\nWorkflow worker runtime import validation failed.\n');
  console.error(error instanceof Error ? error.message : String(error));
  process.exit(1);
}
