"use strict";
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const events = require("./fetch-virtual-server-J6SUa9HS.cjs");
function ok(stdout) {
  return { stdout, stderr: "", exitCode: 0 };
}
function err(stderr, exitCode = 1) {
  return { stdout: "", stderr, exitCode };
}
function parseArgs(args) {
  const result = {
    url: null,
    method: "GET",
    headers: [],
    body: null,
    bodyFile: null,
    maxTimeSeconds: null,
    silent: false,
    includeHeaders: false,
    outputFile: null,
    verbose: false,
    followRedirects: false,
    failOnError: false,
    writeOut: null,
    help: false,
    version: false
  };
  let methodExplicit = false;
  let hasBody = false;
  for (let i = 0; i < args.length; i++) {
    const arg = args[i];
    if (arg.startsWith("--") && arg.includes("=")) {
      const eqIdx = arg.indexOf("=");
      const key = arg.slice(0, eqIdx);
      const val = arg.slice(eqIdx + 1);
      switch (key) {
        case "--request":
          result.method = val.toUpperCase();
          methodExplicit = true;
          break;
        case "--header":
          addHeader(result, val);
          break;
        case "--data":
          setBody(result, val);
          hasBody = true;
          break;
        case "--output":
          result.outputFile = val;
          break;
        case "--max-time":
          result.maxTimeSeconds = parseMaxTimeSeconds(val);
          break;
        case "--write-out":
          result.writeOut = val;
          break;
      }
      continue;
    }
    if (arg.startsWith("--")) {
      switch (arg) {
        case "--help":
          result.help = true;
          break;
        case "--version":
          result.version = true;
          break;
        case "--silent":
          result.silent = true;
          break;
        case "--include":
          result.includeHeaders = true;
          break;
        case "--verbose":
          result.verbose = true;
          break;
        case "--location":
          result.followRedirects = true;
          break;
        case "--fail":
          result.failOnError = true;
          break;
        case "--request":
          result.method = (args[++i] || "GET").toUpperCase();
          methodExplicit = true;
          break;
        case "--header":
          addHeader(result, args[++i] || "");
          break;
        case "--data":
          setBody(result, args[++i] || "");
          hasBody = true;
          break;
        case "--output":
          result.outputFile = args[++i] || null;
          break;
        case "--max-time":
          result.maxTimeSeconds = parseMaxTimeSeconds(args[++i]);
          break;
        case "--write-out":
          result.writeOut = args[++i] || null;
          break;
      }
      continue;
    }
    if (arg.startsWith("-") && arg.length > 1) {
      if (arg.length === 2) {
        switch (arg) {
          case "-X":
            result.method = (args[++i] || "GET").toUpperCase();
            methodExplicit = true;
            continue;
          case "-H":
            addHeader(result, args[++i] || "");
            continue;
          case "-d":
            setBody(result, args[++i] || "");
            hasBody = true;
            continue;
          case "-o":
            result.outputFile = args[++i] || null;
            continue;
          case "-m":
            result.maxTimeSeconds = parseMaxTimeSeconds(args[++i]);
            continue;
          case "-w":
            result.writeOut = args[++i] || null;
            continue;
        }
      }
      const flags = arg.slice(1);
      let consumed = false;
      for (let j = 0; j < flags.length; j++) {
        const ch = flags[j];
        switch (ch) {
          case "s":
            result.silent = true;
            break;
          case "i":
            result.includeHeaders = true;
            break;
          case "v":
            result.verbose = true;
            break;
          case "L":
            result.followRedirects = true;
            break;
          case "f":
            result.failOnError = true;
            break;
          case "X":
            result.method = (args[++i] || "GET").toUpperCase();
            methodExplicit = true;
            consumed = true;
            break;
          case "H":
            addHeader(result, args[++i] || "");
            consumed = true;
            break;
          case "d":
            setBody(result, args[++i] || "");
            hasBody = true;
            consumed = true;
            break;
          case "o":
            result.outputFile = args[++i] || null;
            consumed = true;
            break;
          case "m":
            result.maxTimeSeconds = parseMaxTimeSeconds(args[++i]);
            consumed = true;
            break;
          case "w":
            result.writeOut = args[++i] || null;
            consumed = true;
            break;
        }
        if (consumed) break;
      }
      continue;
    }
    if (!result.url) {
      result.url = arg;
    }
  }
  if (hasBody && !methodExplicit) {
    result.method = "POST";
  }
  return result;
}
function parseMaxTimeSeconds(value) {
  if (!value) {
    return null;
  }
  const parsed = Number.parseFloat(value);
  if (!Number.isFinite(parsed) || parsed < 0) {
    return null;
  }
  return parsed;
}
function addHeader(result, headerStr) {
  const colonIdx = headerStr.indexOf(":");
  if (colonIdx > 0) {
    result.headers.push([
      headerStr.slice(0, colonIdx).trim(),
      headerStr.slice(colonIdx + 1).trim()
    ]);
  }
}
function setBody(result, val) {
  if (val.startsWith("@")) {
    result.bodyFile = val.slice(1);
  } else {
    result.body = val;
  }
}
function isLocalhost(hostname) {
  return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]" || hostname === "::1";
}
function formatResponseHeaders(statusCode, statusMessage, headers) {
  const lines = [`HTTP/1.1 ${statusCode} ${statusMessage}`];
  for (const [key, value] of Object.entries(headers)) {
    lines.push(`${key}: ${value}`);
  }
  lines.push("");
  return lines.join("\r\n");
}
class CurlTimeoutError extends Error {
  constructor(timeoutMs) {
    super(`Operation timed out after ${timeoutMs} milliseconds with 0 bytes received`);
    __publicField(this, "exitCode", 28);
    this.timeoutMs = timeoutMs;
  }
}
async function withCurlTimeout(operation, timeoutMs) {
  if (timeoutMs === null) {
    return operation;
  }
  return new Promise((resolve, reject) => {
    const timeoutId = setTimeout(() => {
      reject(new CurlTimeoutError(timeoutMs));
    }, timeoutMs);
    operation.then(
      (value) => {
        clearTimeout(timeoutId);
        resolve(value);
      },
      (error) => {
        clearTimeout(timeoutId);
        reject(error);
      }
    );
  });
}
async function runCurlCommand(args, _ctx, vfs) {
  const parsed = parseArgs(args);
  if (parsed.help) {
    return ok(HELP_TEXT);
  }
  if (parsed.version) {
    return ok("curl 8.0.0 (almostnode)\n");
  }
  if (!parsed.url) {
    return err("curl: no URL specified\ncurl: try 'curl --help' for more information\n");
  }
  let body = parsed.body;
  if (parsed.bodyFile) {
    try {
      const raw = vfs.readFileSync(parsed.bodyFile);
      body = typeof raw === "string" ? raw : new TextDecoder().decode(raw);
    } catch {
      return err(`curl: (26) Failed to open/read local data from file '${parsed.bodyFile}'
`);
    }
  }
  const headers = {};
  for (const [key, value] of parsed.headers) {
    headers[key] = value;
  }
  if (body && !headers["Content-Type"] && !headers["content-type"]) {
    headers["Content-Type"] = "application/x-www-form-urlencoded";
  }
  try {
    let url;
    try {
      let rawUrl = parsed.url;
      if (!rawUrl.match(/^https?:\/\//)) {
        rawUrl = "http://" + rawUrl;
      }
      url = new URL(rawUrl);
    } catch {
      return err(`curl: (3) URL rejected: ${parsed.url}
`);
    }
    let statusCode;
    let statusMessage;
    let responseHeaders;
    let responseBody;
    let redirectCount = 0;
    const maxRedirects = 10;
    const timeoutMs = parsed.maxTimeSeconds === null ? null : Math.max(0, Math.floor(parsed.maxTimeSeconds * 1e3));
    const deadline = timeoutMs === null ? null : Date.now() + timeoutMs;
    const getRemainingTimeoutMs = () => {
      if (deadline === null || timeoutMs === null) {
        return null;
      }
      return Math.max(0, deadline - Date.now());
    };
    while (true) {
      if (isLocalhost(url.hostname)) {
        const port = parseInt(url.port, 10) || 80;
        const path = url.pathname + url.search;
        const { getServerBridge } = await Promise.resolve().then(() => require("./fetch-virtual-server-J6SUa9HS.cjs")).then((n) => n.serverBridge);
        const bridge = getServerBridge();
        const bodyBuffer = body ? new TextEncoder().encode(body).buffer : void 0;
        const response = await withCurlTimeout(
          bridge.handleRequest(port, parsed.method, path, headers, bodyBuffer),
          getRemainingTimeoutMs()
        );
        statusCode = response.statusCode;
        statusMessage = response.statusMessage || "";
        responseHeaders = response.headers || {};
        responseBody = response.body ? response.body instanceof Uint8Array ? new TextDecoder().decode(response.body) : String(response.body) : "";
      } else {
        try {
          const fetchHeaders = new Headers(headers);
          const fetchOpts = {
            method: parsed.method,
            headers: fetchHeaders,
            redirect: "manual"
          };
          if (body && parsed.method !== "GET" && parsed.method !== "HEAD") {
            fetchOpts.body = body;
          }
          const resp = await withCurlTimeout(
            events.networkFetch(
              url.toString(),
              fetchOpts,
              events.getDefaultNetworkController()
            ),
            getRemainingTimeoutMs()
          );
          statusCode = resp.status;
          statusMessage = resp.statusText || "";
          responseHeaders = {};
          resp.headers.forEach((v, k) => {
            responseHeaders[k] = v;
          });
          responseBody = await resp.text();
        } catch (fetchErr) {
          if (fetchErr instanceof CurlTimeoutError) {
            throw fetchErr;
          }
          return err(`curl: (7) Failed to connect to ${url.hostname}: ${fetchErr.message || fetchErr}
`);
        }
      }
      if (parsed.followRedirects && statusCode >= 300 && statusCode < 400 && responseHeaders["location"]) {
        redirectCount++;
        if (redirectCount > maxRedirects) {
          return err(`curl: (47) Maximum redirects (${maxRedirects}) followed
`);
        }
        try {
          url = new URL(responseHeaders["location"], url);
        } catch {
          return err(`curl: (3) Invalid redirect URL: ${responseHeaders["location"]}
`);
        }
        continue;
      }
      break;
    }
    if (parsed.outputFile) {
      try {
        vfs.writeFileSync(parsed.outputFile, responseBody);
      } catch (writeErr) {
        return err(`curl: (23) Failure writing output to destination: ${writeErr.message || writeErr}
`);
      }
    }
    if (parsed.failOnError && statusCode >= 400) {
      const msg = !parsed.silent ? `curl: (22) The requested URL returned error: ${statusCode}
` : "";
      return { stdout: "", stderr: msg, exitCode: 22 };
    }
    let stdout = "";
    let stderr = "";
    if (parsed.verbose) {
      stderr += `> ${parsed.method} ${url.pathname}${url.search} HTTP/1.1\r
`;
      stderr += `> Host: ${url.host}\r
`;
      for (const [k, v] of Object.entries(headers)) {
        stderr += `> ${k}: ${v}\r
`;
      }
      stderr += ">\r\n";
      stderr += `< HTTP/1.1 ${statusCode} ${statusMessage}\r
`;
      for (const [k, v] of Object.entries(responseHeaders)) {
        stderr += `< ${k}: ${v}\r
`;
      }
      stderr += "<\r\n";
    }
    if (parsed.includeHeaders) {
      stdout += formatResponseHeaders(statusCode, statusMessage, responseHeaders) + "\r\n";
    }
    if (!parsed.outputFile) {
      stdout += responseBody;
    }
    if (parsed.writeOut) {
      stdout += parsed.writeOut.replace(/%\{http_code\}/g, String(statusCode));
    }
    return { stdout, stderr, exitCode: 0 };
  } catch (error) {
    if (error instanceof CurlTimeoutError) {
      return err(`curl: (28) ${error.message}
`, error.exitCode);
    }
    return err(`curl: ${error.message || String(error)}
`);
  }
}
const HELP_TEXT = `Usage: curl [options...] <url>
Options:
 -X, --request <method>   HTTP method (GET, POST, PUT, DELETE, etc.)
 -H, --header <header>    Pass custom header(s) to the server
 -d, --data <data>         HTTP POST data (use @filename to read from file)
 -m, --max-time <seconds>  Maximum time allowed for the transfer
 -o, --output <file>       Write to file instead of stdout
 -s, --silent              Silent mode
 -i, --include             Include response headers in output
 -v, --verbose             Make the operation more talkative
 -L, --location            Follow redirects
 -f, --fail                Fail silently on HTTP errors
 -w, --write-out <format>  Output format after completion
     --help                Show this help
     --version             Show version
`;
exports.runCurlCommand = runCurlCommand;
//# sourceMappingURL=curl-command-BVqcyxJG.cjs.map
