/**
 * O endereço com que o mundo de fora enxerga este admin.
 *
 * `new URL(req.url).origin` devolve o endereço INTERNO. Atrás do Apache o Next
 * atende em `localhost`, e era isso que fazia o link público do pedido de
 * compra sair `http://localhost:3000/pedido-compra/...`: um link que só abre na
 * máquina que o gerou, mandado para um fornecedor que nunca ia conseguir ver o
 * pedido.
 *
 * A ordem é: variável de ambiente (a única que ninguém de fora consegue
 * mexer), depois o cabeçalho que o proxy escreve, depois o `Host`, e só então
 * a URL da requisição.
 */
export function origemPublicaDoAdmin(req: Request) {
  const doAmbiente = String(
    process.env.NEXT_PUBLIC_ADMIN_BASE_URL || process.env.ADMIN_BASE_URL || process.env.NEXT_PUBLIC_ADMIN_URL || ""
  ).trim();
  if (doAmbiente) return semBarraNoFim(doAmbiente);

  return origemDoPedido(req);
}

/**
 * O endereço pelo qual ESTE pedido chegou, sem olhar a variável de ambiente.
 *
 * O mesmo servidor atende por mais de um domínio (o do painel e o do conector
 * dos assistentes). Quem precisa saber por qual deles o pedido veio usa esta
 * função; quem quer o endereço do painel usa a de cima.
 */
export function origemDoPedido(req: Request) {
  const daRequisicao = new URL(req.url);
  const primeiro = (valor: string | null) => String(valor || "").split(",")[0].trim();

  const host = primeiro(req.headers.get("x-forwarded-host")) || primeiro(req.headers.get("host")) || daRequisicao.host;
  if (!host) return semBarraNoFim(daRequisicao.origin);

  return semBarraNoFim(`${protocoloDe(host, req, daRequisicao)}://${host}`);
}

/**
 * O protocolo sai do HOST, e não do cabeçalho.
 *
 * O `x-forwarded-proto` mente aqui por dois motivos somados: a Cloudflare
 * encerra o TLS e conversa com a VPS em http, e o próprio Next preenche o
 * cabeçalho com "http" quando o proxy não mandou nenhum. Um link `http://` num
 * domínio que só existe em https é redirecionamento a mais na mão de quem
 * abre, e mixed content quando a página é embutida.
 *
 * Então: `https` explícito vale sempre; fora isso, endereço de desenvolvimento
 * fica como veio e domínio público é https.
 */
function protocoloDe(host: string, req: Request, daRequisicao: URL) {
  const encaminhado = String(req.headers.get("x-forwarded-proto") || "").split(",")[0].trim().replace(/:$/, "");
  if (encaminhado === "https") return "https";
  if (!ehEnderecoDeDesenvolvimento(host)) return "https";
  return encaminhado || daRequisicao.protocol.replace(/:$/, "") || "http";
}

/** localhost, IP de rede interna, ou qualquer endereço com porta à mostra. */
function ehEnderecoDeDesenvolvimento(host: string) {
  const [nome, porta] = host.toLowerCase().split(":");
  if (porta && porta !== "443") return true;
  if (nome === "localhost" || nome === "127.0.0.1" || nome === "::1" || nome === "[::1]") return true;
  if (nome.endsWith(".local") || nome.endsWith(".localhost")) return true;
  return /^10\./.test(nome) || /^192\.168\./.test(nome) || /^172\.(1[6-9]|2\d|3[01])\./.test(nome);
}

function semBarraNoFim(valor: string) {
  return valor.replace(/\/+$/, "");
}
