"use strict";
/* Socket Lib - Built with esbuild */
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var download_exports = {};
__export(download_exports, {
  httpDownload: () => httpDownload,
  httpDownloadAttempt: () => httpDownloadAttempt
});
module.exports = __toCommonJS(download_exports);
var import_promises = require("node:timers/promises");
var import_safe = require("../fs/safe");
var import_buffer = require("../primordials/buffer");
var import_error = require("../primordials/error");
var import_math = require("../primordials/math");
var import_number = require("../primordials/number");
var import_promise = require("../primordials/promise");
var import_internal = require("./_internal");
var import_request = require("./request");
var import_response_types = require("./response-types");
async function httpDownload(url, destPath, options) {
  const {
    ca,
    followRedirects = true,
    headers = {},
    logger,
    maxRedirects = 5,
    onProgress,
    progressInterval = 10,
    retries = 0,
    retryDelay = 1e3,
    sha256,
    timeout = 12e4
  } = { __proto__: null, ...options };
  let progressCallback;
  if (onProgress) {
    progressCallback = onProgress;
  } else if (logger) {
    let lastPercent = 0;
    progressCallback = (downloaded, total) => {
      const percent = total === 0 ? 0 : (0, import_math.MathFloor)(downloaded / total * 100);
      if (percent >= lastPercent + progressInterval) {
        logger.log(
          `  Progress: ${percent}% (${(downloaded / 1024 / 1024).toFixed(1)} MB / ${(total / 1024 / 1024).toFixed(1)} MB)`
        );
        lastPercent = percent;
      }
    };
  }
  const crypto = (0, import_internal.getCrypto)();
  const fs = (0, import_internal.getFs)();
  const tempSuffix = crypto.randomBytes(6).toString("hex");
  const tempPath = `${destPath}.${tempSuffix}.download`;
  if (fs.existsSync(tempPath)) {
    await (0, import_safe.safeDelete)(tempPath);
  }
  let lastError;
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      const result = await httpDownloadAttempt(url, tempPath, {
        ca,
        followRedirects,
        headers,
        maxRedirects,
        onProgress: progressCallback,
        timeout
      });
      if (sha256) {
        const fileContent = await fs.promises.readFile(tempPath);
        const computedHash = crypto.createHash("sha256").update(fileContent).digest("hex");
        const expectedHash = sha256.toLowerCase();
        if (computedHash.length !== expectedHash.length || !crypto.timingSafeEqual(
          (0, import_buffer.BufferFrom)(computedHash),
          Buffer.from(expectedHash)
        )) {
          await (0, import_safe.safeDelete)(tempPath);
          throw new import_error.ErrorCtor(
            `Checksum verification failed for ${url}
Expected: ${expectedHash}
Computed: ${computedHash}`
          );
        }
      }
      await fs.promises.rename(tempPath, destPath);
      return {
        ...result,
        path: destPath
      };
    } catch (e) {
      lastError = e;
      if (fs.existsSync(tempPath)) {
        await (0, import_safe.safeDelete)(tempPath);
      }
      if (attempt === retries) {
        break;
      }
      const delayMs = retryDelay * 2 ** attempt;
      await (0, import_promises.setTimeout)(delayMs);
    }
  }
  throw lastError || new import_error.ErrorCtor("Download failed after retries");
}
async function httpDownloadAttempt(url, destPath, options) {
  const {
    ca,
    followRedirects = true,
    headers = {},
    maxRedirects = 5,
    onProgress,
    timeout = 12e4
  } = { __proto__: null, ...options };
  const response = await (0, import_request.httpRequestAttempt)(url, {
    ca,
    followRedirects,
    headers,
    maxRedirects,
    method: "GET",
    stream: true,
    timeout
  });
  if (!response.ok) {
    throw new import_response_types.HttpResponseError(
      response,
      `Download failed: HTTP ${response.status} ${response.statusText}`
    );
  }
  const res = response.rawResponse;
  if (!res) {
    throw new import_error.ErrorCtor("Stream response missing rawResponse");
  }
  const { createWriteStream } = (0, import_internal.getFs)();
  const totalSize = (0, import_number.NumberParseInt)(
    response.headers["content-length"] || "0",
    10
  );
  return await new import_promise.PromiseCtor((resolve, reject) => {
    let downloadedSize = 0;
    const fileStream = createWriteStream(destPath);
    const cleanupPartial = () => {
      ;
      (async () => {
        try {
          await (0, import_safe.safeDelete)(destPath);
        } catch {
        }
      })();
    };
    fileStream.on("error", (error) => {
      fileStream.destroy();
      cleanupPartial();
      reject(
        new import_error.ErrorCtor(`Failed to write file: ${error.message}`, {
          cause: error
        })
      );
    });
    res.on("data", (chunk) => {
      downloadedSize += chunk.length;
      if (onProgress && totalSize > 0) {
        onProgress(downloadedSize, totalSize);
      }
    });
    fileStream.on("finish", () => {
      resolve({
        headers: response.headers,
        ok: true,
        path: destPath,
        size: downloadedSize,
        status: response.status,
        statusText: response.statusText
      });
    });
    res.on("error", (error) => {
      fileStream.destroy();
      cleanupPartial();
      reject(error);
    });
    res.pipe(fileStream);
  });
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  httpDownload,
  httpDownloadAttempt
});
