import { spawnSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';

const watchPath = process.argv[2];
const isWorkersBuild = Boolean(process.env.WORKERS_CI || process.env.WORKERS_CI_COMMIT_SHA);
const forceDeploy = process.env.FORCE_DEPLOY === '1';
const __dirname = dirname(fileURLToPath(import.meta.url));
const noticeBindingName = 'NOTICE_STORE';

if (!watchPath) {
  console.error('Usage: node deploy-if-changed.mjs <watch-path>');
  process.exit(1);
}

function run(command, args, options = {}) {
  return spawnSync(command, args, {
    encoding: 'utf8',
    shell: process.platform === 'win32',
    ...options,
  });
}

function deploy() {
  runPreDeploySetupIfNeeded();
  console.log(`Running wrangler deploy for ${watchPath}.`);

  const result = spawnSync('npx', ['wrangler', 'deploy'], {
    stdio: 'inherit',
    shell: process.platform === 'win32',
  });

  process.exit(result.status ?? 1);
}

function runPreDeploySetupIfNeeded() {
  if (String(watchPath || '').replace(/\\/g, '/') !== 'analytics/worker') {
    return;
  }

  const workerConfigPath = resolve(__dirname, '../worker/wrangler.jsonc');
  const source = readFileSync(workerConfigPath, 'utf8');
  if (hasNoticeStoreBinding(source)) {
    console.log('NOTICE_STORE KV namespace already configured; skipping setup.');
    return;
  }

  console.log('NOTICE_STORE KV namespace is not configured; running setup.');
  const setupScript = resolve(__dirname, 'setup-notice-kv.mjs');
  const result = spawnSync(process.execPath, [setupScript], {
    stdio: 'inherit',
    shell: process.platform === 'win32',
  });

  if (result.status !== 0) {
    process.exit(result.status ?? 1);
  }
}

function hasNoticeStoreBinding(source) {
  const escapedBinding = noticeBindingName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  const pattern = new RegExp(`\\{[\\s\\S]*?"binding"\\s*:\\s*"${escapedBinding}"[\\s\\S]*?"id"\\s*:\\s*"[^"<]+"[\\s\\S]*?\\}`);
  return pattern.test(source);
}

function getTrimmedStdout(result) {
  return String(result.stdout || '').trim();
}

if (!isWorkersBuild || forceDeploy) {
  deploy();
}

const repoRootResult = run('git', ['rev-parse', '--show-toplevel']);
if (repoRootResult.status !== 0) {
  console.warn('Unable to find git root, deploying normally.');
  deploy();
}

const repoRoot = getTrimmedStdout(repoRootResult);
const parentResult = run('git', ['rev-parse', 'HEAD^'], { cwd: repoRoot });
if (parentResult.status !== 0) {
  console.warn('Unable to find parent commit, deploying normally.');
  deploy();
}

const parentCommit = getTrimmedStdout(parentResult);
const diffResult = run('git', ['diff', '--name-only', parentCommit, 'HEAD', '--', watchPath], { cwd: repoRoot });
if (diffResult.status !== 0) {
  console.warn('Unable to inspect changed files, deploying normally.');
  deploy();
}

const changedFiles = getTrimmedStdout(diffResult);
if (!changedFiles) {
  console.log(`No changes under ${watchPath}; skipping wrangler deploy.`);
  process.exit(0);
}

console.log(`Changes detected under ${watchPath}:`);
console.log(changedFiles);
deploy();
