#!/usr/bin/env node
import { spawn } from 'node:child_process';
import { existsSync } from 'node:fs';
import { createRequire } from 'node:module';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';

const require = createRequire(import.meta.url);
const argv = process.argv.slice(2);
const callerCwd = process.cwd();

const platformPackages = {
  'darwin-arm64': '@gradial/aci-cli-darwin-arm64',
  'darwin-x64': '@gradial/aci-cli-darwin-x64',
  'linux-arm64': '@gradial/aci-cli-linux-arm64',
  'linux-x64': '@gradial/aci-cli-linux-x64',
  'win32-x64': '@gradial/aci-cli-win32-x64',
};

const platformKey = `${process.platform}-${process.arch}`;
const packageName = platformPackages[platformKey];

if (!packageName) {
  console.error(`Unsupported platform for aci: ${platformKey}`);
  process.exit(1);
}

const binName = process.platform === 'win32' ? 'aci.exe' : 'aci';
const shimDir = dirname(fileURLToPath(import.meta.url));
const repoRoot = resolve(shimDir, '../../..');

function resolveBundledBinary() {
  const binaryPath = join(shimDir, binName);
  return existsSync(binaryPath) ? binaryPath : null;
}

function resolvePackagedBinary() {
  try {
    const packageJsonPath = require.resolve(`${packageName}/package.json`);
    const binaryPath = join(dirname(packageJsonPath), 'bin', binName);

    return existsSync(binaryPath) ? binaryPath : null;
  } catch {
    return null;
  }
}

function resolveWorkspaceBinary() {
  const binaryPath = resolve(shimDir, '..', '..', 'packages', `cli-${platformKey}`, 'bin', binName);

  return existsSync(binaryPath) ? binaryPath : null;
}

const binaryPath = resolveBundledBinary() ?? resolvePackagedBinary() ?? resolveWorkspaceBinary();
const fallback = binaryPath ? null : resolveGoFallback();

if (!binaryPath && !fallback) {
  console.error(
    [
      `Could not find the aci binary for ${platformKey}.`,
      `Install ${packageName} or build the local CLI package with ./scripts/build-cli.sh.`,
    ].join(' '),
  );
  process.exit(1);
}

const child = binaryPath
  ? spawn(binaryPath, argv, { stdio: 'inherit' })
  : spawn(fallback.command, fallback.args, {
      cwd: fallback.cwd,
      stdio: 'inherit',
    });

child.on('error', (error) => {
  console.error(`Failed to run aci: ${error.message}`);
  process.exit(1);
});

child.on('exit', (code, signal) => {
  if (signal) {
    process.kill(process.pid, signal);
    return;
  }

  process.exit(code ?? 1);
});

function resolveGoFallback() {
  const goModPath = join(repoRoot, 'go.mod');
  const commandDir = join(repoRoot, 'cmd', 'aci');

  if (!existsSync(goModPath) || !existsSync(commandDir)) {
    return null;
  }

  return {
    command: 'go',
    args: ['run', './cmd/aci', ...normalizeArgsForGoFallback(argv)],
    cwd: repoRoot,
  };
}

function normalizeArgsForGoFallback(args) {
  const pathFlags = new Set(['-s', '--site-dir', '--content', '--out']);
  const normalized = [];
  let hasSiteDir = false;

  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];

    if (pathFlags.has(arg)) {
      normalized.push(arg);
      if (arg === '-s' || arg === '--site-dir') {
        hasSiteDir = true;
      }

      const value = args[index + 1];
      if (value !== undefined) {
        normalized.push(normalizePathArg(value));
        index += 1;
      }
      continue;
    }

    if (arg.startsWith('--site-dir=')) {
      hasSiteDir = true;
      normalized.push(normalizePathFlagValue(arg));
      continue;
    }

    if (arg.startsWith('--content=') || arg.startsWith('--out=')) {
      normalized.push(normalizePathFlagValue(arg));
      continue;
    }

    normalized.push(arg);
  }

  return hasSiteDir ? normalized : ['--site-dir', callerCwd, ...normalized];
}

function normalizePathFlagValue(arg) {
  const separator = arg.indexOf('=');
  return `${arg.slice(0, separator + 1)}${normalizePathArg(arg.slice(separator + 1))}`;
}

function normalizePathArg(value) {
  if (!value || value.startsWith('-') || isAbsolutePath(value)) {
    return value;
  }

  return resolve(callerCwd, value);
}

function isAbsolutePath(value) {
  return value.startsWith('/') || /^[A-Za-z]:[\\/]/.test(value);
}
