#!/usr/bin/env node
import net from "node:net";

const [proxyHost, proxyPortRaw, targetHost, targetPortRaw] = process.argv.slice(2);
const proxyPort = Number.parseInt(proxyPortRaw || "", 10);
const targetPort = Number.parseInt(targetPortRaw || "", 10);
if (!proxyHost || !Number.isInteger(proxyPort) || !targetHost || !Number.isInteger(targetPort)) {
  console.error("usage: hwlab-github-proxy-connect <proxyHost> <proxyPort> <targetHost> <targetPort>");
  process.exit(64);
}

const socket = net.createConnection({ host: proxyHost, port: proxyPort });
let buffer = Buffer.alloc(0);

socket.setTimeout(10000, () => {
  console.error("proxy connect timeout " + proxyHost + ":" + proxyPort + " -> " + targetHost + ":" + targetPort);
  socket.destroy();
  process.exit(65);
});

socket.on("connect", () => {
  socket.write("CONNECT " + targetHost + ":" + targetPort + " HTTP/1.1\r\nHost: " + targetHost + ":" + targetPort + "\r\nProxy-Connection: Keep-Alive\r\n\r\n");
});

socket.on("error", (error) => {
  console.error("proxy connect failed: " + error.message);
  process.exit(66);
});

function onData(chunk) {
  buffer = Buffer.concat([buffer, chunk]);
  const headerEnd = buffer.indexOf("\r\n\r\n");
  if (headerEnd === -1 && buffer.length < 8192) return;
  const head = buffer.slice(0, headerEnd + 4).toString("latin1");
  const statusLine = head.split("\r\n", 1)[0] || "";
  const statusCode = Number.parseInt(statusLine.split(" ")[1] || "", 10);
  if (!statusLine.startsWith("HTTP/1.") || !Number.isInteger(statusCode) || statusCode < 200 || statusCode > 299) {
    console.error("proxy CONNECT rejected: " + (statusLine || "missing-status"));
    socket.destroy();
    process.exit(67);
  }
  socket.off("data", onData);
  socket.setTimeout(0);
  const rest = buffer.slice(headerEnd + 4);
  if (rest.length) process.stdout.write(rest);
  process.stdin.pipe(socket);
  socket.pipe(process.stdout);
}

socket.on("data", onData);
socket.on("close", () => process.exit(0));