#!/usr/bin/env node
'use strict';

const http = require('http');
const https = require('https');
const fs = require('fs');
const path = require('path');

const rootDir = path.join(__dirname, '..');
const pkg = JSON.parse(fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8'));
const version = `v${pkg.version}`;

const targets = [
  'skill-cli-darwin-arm64',
  'skill-cli-darwin-x64',
  'skill-cli-linux-arm64',
  'skill-cli-linux-x64',
  'skill-cli-win32-x64.exe',
];

const args = process.argv.slice(2);
let rootURL = '';
let scriptRoot = '';
let binaryBaseURL = '';
let includeAllBinaries = false;

function usage() {
  console.log(`Usage:
  node scripts/check-install-host.js --root URL [--all-binaries]
  node scripts/check-install-host.js --script-root URL --base-url URL [--all-binaries]

Examples:
  node scripts/check-install-host.js --root https://intranet.example.com/skill-cli
  node scripts/check-install-host.js \\
    --script-root https://gitee.com/marvin-dev/skill-cli-creator/raw/${version} \\
    --base-url https://gitee.com/marvin-dev/skill-cli-creator/raw/${version}/bin/targets

Checks installer scripts and the Windows binary by default. Pass --all-binaries
to verify every bundled platform binary.`);
}

for (let i = 0; i < args.length; i += 1) {
  const arg = args[i];
  if (arg === '--root') {
    rootURL = args[i + 1] || '';
    i += 1;
  } else if (arg === '--script-root') {
    scriptRoot = args[i + 1] || '';
    i += 1;
  } else if (arg === '--base-url') {
    binaryBaseURL = args[i + 1] || '';
    i += 1;
  } else if (arg === '--all-binaries') {
    includeAllBinaries = true;
  } else if (arg === '-h' || arg === '--help') {
    usage();
    process.exit(0);
  } else {
    console.error(`unknown option: ${arg}`);
    usage();
    process.exit(2);
  }
}

function trimSlash(value) {
  return value.replace(/\/+$/, '');
}

if (rootURL) {
  rootURL = trimSlash(rootURL);
  scriptRoot = `${rootURL}`;
  binaryBaseURL = `${rootURL}/bin/targets`;
}

if (!scriptRoot || !binaryBaseURL) {
  console.error('missing --root, or both --script-root and --base-url');
  usage();
  process.exit(2);
}

scriptRoot = trimSlash(scriptRoot);
binaryBaseURL = trimSlash(binaryBaseURL);

const checks = [
  `${scriptRoot}/scripts/install.ps1`,
  `${scriptRoot}/scripts/install.sh`,
];

const binaryNames = includeAllBinaries ? targets : ['skill-cli-win32-x64.exe'];
for (const target of binaryNames) {
  checks.push(`${binaryBaseURL}/${target}`);
}

function request(url, method, redirectsRemaining = 5) {
  return new Promise((resolve) => {
    const lib = url.startsWith('https:') ? https : http;
    const req = lib.request(url, { method, timeout: 15000 }, (res) => {
      if (
        res.statusCode >= 300 &&
        res.statusCode < 400 &&
        res.headers.location &&
        redirectsRemaining > 0
      ) {
        res.resume();
        const redirectedURL = new URL(res.headers.location, url).toString();
        resolve(request(redirectedURL, method, redirectsRemaining - 1));
        return;
      }

      res.resume();
      res.on('end', () => {
        resolve({
          url,
          statusCode: res.statusCode || 0,
          contentLength: res.headers['content-length'] || '',
          ok: res.statusCode >= 200 && res.statusCode < 300,
        });
      });
    });
    req.on('timeout', () => {
      req.destroy(new Error('timeout'));
    });
    req.on('error', (err) => {
      resolve({ url, statusCode: 0, contentLength: '', ok: false, error: err.message });
    });
    req.end();
  });
}

async function checkURL(url) {
  const head = await request(url, 'HEAD');
  if (head.ok) {
    return head;
  }
  const get = await request(url, 'GET');
  return get.ok ? get : head;
}

(async () => {
  let failed = false;
  for (const url of checks) {
    const result = await checkURL(url);
    if (result.ok) {
      const size = result.contentLength ? ` (${result.contentLength} bytes)` : '';
      console.log(`OK   ${url}${size}`);
    } else {
      failed = true;
      const detail = result.error ? result.error : `HTTP ${result.statusCode}`;
      console.error(`FAIL ${url} - ${detail}`);
    }
  }
  process.exit(failed ? 1 : 0);
})();
