const fs = require("fs");
const path = require("path");
const net = require("net");

const repoRoot = path.join(__dirname, "..", "..");

function parseBoolean(value) {
  if (value == null || value === "") return null;
  const normalized = String(value).trim().toLowerCase();
  if (["1", "true", "yes", "on", "development", "dev"].includes(normalized)) return true;
  if (["0", "false", "no", "off", "production", "prod"].includes(normalized)) return false;
  return null;
}

function normalizeHostname(value) {
  const raw = String(value || "").trim().toLowerCase();
  if (!raw) return "";
  if (raw.startsWith("[") && raw.endsWith("]")) return raw.slice(1, -1);
  return raw.replace(/^::ffff:/, "");
}

function isLoopbackHostname(value) {
  const hostname = normalizeHostname(value);
  if (!hostname) return false;
  if (hostname === "localhost" || hostname === "::1") return true;
  if (net.isIP(hostname) === 4) return hostname.startsWith("127.");
  return false;
}

function requestHostname(req) {
  const host = String(req?.hostname || req?.get?.("host") || "").trim();
  if (!host) return "";
  if (host.startsWith("[")) return host.slice(1, host.indexOf("]"));
  return host.split(":")[0];
}

function isStrictLoopbackRequest(req) {
  const remoteAddress = normalizeHostname(req?.socket?.remoteAddress || req?.connection?.remoteAddress || "");
  return isLoopbackHostname(requestHostname(req)) && isLoopbackHostname(remoteAddress);
}

function resolveRuntimeEnvironment(options = {}) {
  const env = options.env || process.env;
  const root = options.repoRoot || repoRoot;
  const bindHost = String(env.LUMI_HOST || "").trim();
  const explicitMode = parseBoolean(env.LUMI_DEV_MODE ?? env.LUMI_DEVELOPMENT);
  const nodeEnvironment = String(env.NODE_ENV || "").trim().toLowerCase();
  const sourceCheckout = fs.existsSync(path.join(root, ".git"));

  let isDevelopment;
  let reason;
  if (explicitMode !== null) {
    isDevelopment = explicitMode;
    reason = explicitMode ? "explicit development override" : "explicit production override";
  } else if (nodeEnvironment === "production") {
    isDevelopment = false;
    reason = "NODE_ENV=production";
  } else if (nodeEnvironment === "development") {
    isDevelopment = true;
    reason = "NODE_ENV=development";
  } else if (isLoopbackHostname(bindHost)) {
    isDevelopment = true;
    reason = `loopback bind host (${bindHost})`;
  } else if (sourceCheckout) {
    isDevelopment = true;
    reason = "source checkout detected";
  } else {
    isDevelopment = false;
    reason = "packaged runtime default";
  }

  const snapshot = {
    mode: isDevelopment ? "development" : "production",
    isDevelopment,
    isProduction: !isDevelopment,
    development: isDevelopment,
    production: !isDevelopment,
    devMode: isDevelopment,
    sourceCheckout,
    bindHost: bindHost || null,
    localhostBound: isLoopbackHostname(bindHost),
    reason,
    isLoopbackHostname,
    isStrictLoopbackRequest,
    allowsLocalDevelopmentUpdates(req) {
      return isDevelopment && isStrictLoopbackRequest(req);
    }
  };
  return Object.freeze(snapshot);
}

function installGlobalRuntimeEnvironment(options = {}) {
  const runtime = resolveRuntimeEnvironment(options);
  global.lumiRuntime = runtime;
  global.lumiEnvironment = runtime;
  return runtime;
}

module.exports = {
  installGlobalRuntimeEnvironment,
  isLoopbackHostname,
  isStrictLoopbackRequest,
  normalizeHostname,
  parseBoolean,
  requestHostname,
  resolveRuntimeEnvironment
};
