const http = require("http");
const https = require("https");

const MAX_RESPONSE_BYTES = 25_000_000;

function createHttpClient({ timeoutMs = 8000 } = {}) {
  function fetchBody(url, options = {}) {
    const {
      allowHttp = false,
      label = "Request",
      statusLabel = label,
      timeoutMessage = `${label} request timed out`
    } = options;
    const urlString = String(url || "");
    const isHttps = urlString.startsWith("https:");
    const isHttp = urlString.startsWith("http:");
    const client = isHttps ? https : isHttp && allowHttp ? http : null;

    return new Promise((resolve, reject) => {
      if (!client) {
        reject(new Error(`${label} URL must start with ${allowHttp ? "http:// or https://" : "https://"}.`));
        return;
      }

      const request = client
        .get(urlString, response => {
          response.setEncoding("utf8");
          let body = "";
          response.on("data", chunk => {
            body += chunk;
            if (body.length > MAX_RESPONSE_BYTES) {
              request.destroy(new Error(`${label} response was too large.`));
            }
          });
          response.on("end", () => {
            if (response.statusCode < 200 || response.statusCode >= 300) {
              reject(new Error(`${statusLabel} returned HTTP ${response.statusCode}`));
              return;
            }
            resolve(body);
          });
        })
        .on("error", reject);

      request.setTimeout(timeoutMs, () => {
        request.destroy(new Error(timeoutMessage));
      });
    });
  }

  async function fetchJson(url, label = "Race Monitor") {
    const body = await fetchBody(url, {
      label,
      statusLabel: label,
      timeoutMessage: `${label} request timed out`
    });
    try {
      return JSON.parse(body);
    } catch (err) {
      throw new Error(`Could not parse ${label} response: ${err.message}`);
    }
  }

  function fetchText(url) {
    return fetchBody(url, {
      label: "Request",
      statusLabel: "Request",
      timeoutMessage: "Request timed out"
    });
  }

  function fetchHttpText(url) {
    return fetchBody(url, {
      allowHttp: true,
      label: "vMix",
      statusLabel: "vMix",
      timeoutMessage: "vMix request timed out"
    });
  }

  return { fetchJson, fetchText, fetchHttpText };
}

module.exports = { createHttpClient };
