import { getConfig } from "../config.js";
import { createLogger } from "../logger.js";
const log = createLogger("fetch");
class TlsTierUnavailableError extends Error {
  constructor(cause) {
    super("tls_tier_unavailable");
    this.cause = cause;
    this.name = "TlsTierUnavailableError";
  }
  cause;
}
let _backendPromise = null;
let _backendCached = null;
function _resetTlsBackend() {
  _backendPromise = null;
  _backendCached = null;
}
let _testBackendOverride = null;
function _setTlsBackendForTests(backend) {
  _testBackendOverride = backend;
  _resetTlsBackend();
}
const WREQ_MODULE_ID = "wreq-js";
async function loadBackend() {
  if (_testBackendOverride) return _testBackendOverride;
  if (_backendCached) return _backendCached;
  if (_backendPromise) return _backendPromise;
  _backendPromise = (async () => {
    try {
      const mod = await import(WREQ_MODULE_ID);
      const fetchFn = mod.fetch ?? mod.default?.fetch;
      if (!fetchFn) {
        throw new Error("wreq-js: no fetch export found");
      }
      const backend = { fetch: fetchFn };
      _backendCached = backend;
      return backend;
    } catch (err) {
      _backendPromise = null;
      throw new TlsTierUnavailableError(err);
    }
  })();
  return _backendPromise;
}
function headersToRecord(h) {
  const out = {};
  if (!h) return out;
  if (typeof h.entries === "function") {
    for (const [k, v] of h.entries()) {
      out[k.toLowerCase()] = v;
    }
  } else if (typeof h.forEach === "function") {
    h.forEach((value, key) => {
      out[key.toLowerCase()] = value;
    });
  }
  return out;
}
async function tlsFetch(url, options = {}) {
  const backend = await loadBackend();
  const config = getConfig();
  const timeoutMs = options.timeoutMs ?? config.fetchTimeoutMs;
  let signal;
  try {
    signal = AbortSignal.timeout(timeoutMs);
  } catch {
    signal = void 0;
  }
  const response = await backend.fetch(url, {
    headers: options.headers,
    browser: config.tlsBrowser,
    signal
  });
  const headers = headersToRecord(response.headers);
  const contentType = headers["content-type"] ?? "";
  const isPdf = contentType.includes("application/pdf");
  let html = "";
  let rawBuffer;
  if (isPdf && typeof response.arrayBuffer === "function") {
    const ab = await response.arrayBuffer();
    rawBuffer = Buffer.from(ab);
  } else {
    html = await response.text();
  }
  return {
    url,
    finalUrl: response.url ?? url,
    html,
    contentType,
    statusCode: response.status,
    headers,
    rawBuffer
  };
}
const ANTI_BOT_STATUS = /* @__PURE__ */ new Set([403, 429, 503]);
const CHALLENGE_MARKERS = [
  "cf-browser-verification",
  "Just a moment",
  "_cfChlOpt",
  // DataDome inserts a `dd-loader` sensor and inline script that begins
  // `window._dd_s` — either is a strong "blocked" signal.
  "dd-loader",
  "_dd_s"
];
function isAntiBotStatus(status) {
  return ANTI_BOT_STATUS.has(status);
}
function hasChallengeBody(html) {
  if (!html) return false;
  const slice = html.length > 32768 ? html.slice(0, 32768) : html;
  for (const marker of CHALLENGE_MARKERS) {
    if (slice.includes(marker)) return true;
  }
  return false;
}
function isRateLimit(statusCode, html) {
  if (statusCode !== 429) return false;
  return !hasChallengeBody(html);
}
function isAntiBotSignal(statusCode, html) {
  if (isRateLimit(statusCode, html)) return false;
  return isAntiBotStatus(statusCode) || hasChallengeBody(html);
}
function looksJsRequired(html) {
  if (!html) return true;
  const slice = html.length > 32768 ? html.slice(0, 32768) : html;
  return /enable javascript/i.test(slice);
}
function describeAntiBot(statusCode, html) {
  if (isAntiBotStatus(statusCode)) return `status_${statusCode}`;
  if (hasChallengeBody(html)) return "challenge_body";
  return null;
}
void log;
export {
  TlsTierUnavailableError,
  _resetTlsBackend,
  _setTlsBackendForTests,
  describeAntiBot,
  hasChallengeBody,
  isAntiBotSignal,
  isAntiBotStatus,
  isRateLimit,
  looksJsRequired,
  tlsFetch
};
//# sourceMappingURL=tls-tier.js.map