const path = require('path');
const fs = require('fs');
const os = require('os');
const { spawnSync } = require('child_process');

// Determine platform and architecture
const platform = os.platform();
const arch = os.arch();

// Map Node.js arch to our naming convention
const archMap = {
  'x64': 'x64',
  'ia32': 'x86',
  'arm64': 'arm64',
  'arm': 'arm'
};

const normalizedArch = archMap[arch] || arch;
const platformArch = `${platform}-${normalizedArch}`;

// Check if we're in node_modules (installed package) or development
const isInstalledPackage = __dirname.includes('node_modules');

const prebuildPath = path.join(__dirname, 'prebuilds', platformArch, 'HypertubeNodejsRuntimeAddon.node');
const buildPath = path.join(__dirname, 'build', 'Release', 'HypertubeNodejsRuntimeAddon.node');

let addon = null;

/**
 * Attempt to build the native addon using node-gyp.
 * Tries `npx node-gyp rebuild` first, then `node-gyp rebuild`.
 * Throws a detailed error if node-gyp is missing or the build fails.
 */
function buildWithNodeGyp() {
  console.log('[HypertubeNodejsRuntimeAddon] No prebuilt binary found. Attempting to build with node-gyp...');

  const commands = [
    { cmd: 'npx', args: ['node-gyp', 'rebuild'], label: 'npx node-gyp rebuild' },
    { cmd: 'node-gyp', args: ['rebuild'], label: 'node-gyp rebuild' }
  ];

  let lastError = null;

  for (const { cmd, args, label } of commands) {
    console.log(`[HypertubeNodejsRuntimeAddon] Running: ${label} (cwd=${__dirname})`);

    const result = spawnSync(cmd, args, {
      cwd: __dirname,
      stdio: 'inherit', // Show compiler / node-gyp output to user
      shell: process.platform === 'win32' // Help with command resolution on Windows
    });

    if (result.error) {
      lastError = result.error;
      // ENOENT -> command not found, try next option
      if (result.error.code === 'ENOENT') {
        console.warn(`[HypertubeNodejsRuntimeAddon] Command not found: ${cmd}. Trying next option...`);
        continue;
      }
      // Other spawn error — no point trying further
      break;
    }

    if (result.status === 0) {
      console.log('[HypertubeNodejsRuntimeAddon] node-gyp build completed successfully.');
      return;
    }

    // Non-zero exit code
    lastError = new Error(`${label} exited with code ${result.status}`);
    console.error(`[HypertubeNodejsRuntimeAddon] ${lastError.message}`);
    // If this failed, trying the other variant is unlikely to help, but we can continue anyway.
  }

  // If we reach here, build failed
  let msg = 'Failed to build HypertubeNodejsRuntimeAddon native addon with node-gyp.\n';

  if (lastError && lastError.code === 'ENOENT') {
    msg +=
        'It looks like `node-gyp` is not installed or not available in your PATH.\n' +
        'Install it globally with:\n' +
        '  npm install -g node-gyp\n' +
        'or add it as a devDependency:\n' +
        '  npm install --save-dev node-gyp\n';
  } else {
    msg +=
        (lastError ? `Last error: ${lastError.message}\n` : '') +
        'Please ensure you have a working C/C++ compiler toolchain and Python installed.\n' +
        'Refer to the official node-gyp documentation for platform-specific requirements.';
  }

  throw new Error(msg);
}

// 1. Try to load precompiled binary first
if (fs.existsSync(prebuildPath)) {
  try {
    addon = require(prebuildPath);
  } catch (err) {
    // If we're in an installed package, don't fall back - fail fast with clear error
    if (isInstalledPackage) {
      throw new Error(
          `Failed to load precompiled binary for ${platformArch}.\n` +
          `Path: ${prebuildPath}\n` +
          `Error: ${err.message}\n` +
          `This may indicate a corrupted or incompatible binary. Please reinstall the package.`
      );
    }
    console.warn(`Failed to load precompiled binary from ${prebuildPath}:`, err.message);
  }
}

// 2. If no prebuild loaded and we're in development, ensure we have a build by running node-gyp if needed
if (!addon && !isInstalledPackage) {
  // If neither prebuild nor build artifact exist, try to build
  if (!fs.existsSync(prebuildPath) && !fs.existsSync(buildPath)) {
    buildWithNodeGyp();
  }

  // After attempted build, try build/Release path
  if (fs.existsSync(buildPath)) {
    try {
      addon = require(buildPath);
    } catch (err) {
      // Check if error is due to platform mismatch
      if (err.message && (err.message.includes('invalid ELF header') || err.message.includes('bad image'))) {
        console.warn(`Binary in build/Release appears to be for a different platform. Skipping.`);
      } else {
        console.warn(`Failed to load binary from ${buildPath}:`, err.message);
      }
    }
  }
}

// 3. If still no addon, try node-gyp default / bindings path (development only)
if (!addon && !isInstalledPackage) {
  try {
    addon = require('./build/Release/HypertubeNodejsRuntimeAddon.node');
  } catch (err) {
    // Check if error is due to platform mismatch
    if (err.message && (err.message.includes('invalid ELF header') || err.message.includes('bad image'))) {
      console.warn(`Binary in build/Release appears to be for a different platform. Skipping.`);
    }
    // Last resort: try node-gyp's default location via bindings
    try {
      addon = require('bindings')('HypertubeNodejsRuntimeAddon.node');
    } catch (bindingsErr) {
      // Only throw if we haven't already tried prebuilds
      if (!fs.existsSync(prebuildPath)) {
        throw new Error(
            `Failed to load HypertubeNodejsRuntimeAddon native addon.\n` +
            `Platform: ${platformArch}\n` +
            `Tried locations:\n` +
            `  - ${prebuildPath}\n` +
            `  - ${buildPath}\n` +
            `  - bindings('HypertubeNodejsRuntimeAddon.node')\n` +
            `Original error: ${bindingsErr.message}\n` +
            `Please ensure the native addon is precompiled for your platform or node-gyp is installed and working to build it.`
        );
      }
    }
  }
}

// 4. Final check - if we still don't have an addon, throw a clear error
if (!addon) {
  const triedPaths = [prebuildPath];
  if (!isInstalledPackage) {
    triedPaths.push(buildPath, "bindings('HypertubeNodejsRuntimeAddon.node')");
  }

  throw new Error(
      `Failed to load HypertubeNodejsRuntimeAddon native addon.\n` +
      `Platform: ${platformArch}\n` +
      `Tried locations:\n` +
      triedPaths.map(p => `  - ${p}`).join('\n') + '\n' +
      `Please ensure the native addon is precompiled for your platform or node-gyp is installed and able to build it.`
  );
}

module.exports = addon;
