import { replaceVariables as U } from "@scalar/helpers/regex/replace-variables";
import { isRelativePath as b } from "@scalar/helpers/url/is-relative-path";
import { makeUrlAbsolute as x } from "@scalar/helpers/url/make-url-absolute";
import { shouldUseProxy as A } from "@scalar/helpers/url/redirect-to-proxy";
import { encode as E, fromUint8Array as k } from "js-base64";
const S = (e) => {
  if (!e?.url) return;
  const s = Object.entries(e.variables ?? {}).reduce(
    (i, [a, c]) => {
      const h = c.value || c.default;
      return h && (i[a] = h), i;
    },
    {}
  );
  return U(e.url, s);
}, w = (e) => {
  const s = S(e);
  return s ? b(s) ? typeof window > "u" ? {} : { basePath: s } : { baseUrl: s } : {};
}, C = () => {
  const e = new Uint8Array(32);
  return crypto.getRandomValues(e), k(e, !0);
}, T = async (e, s) => {
  if (s === "plain")
    return e;
  if (typeof crypto?.subtle?.digest != "function")
    return console.warn("SHA-256 is only supported when using https, using a plain text code challenge instead."), e;
  const a = new TextEncoder().encode(e), c = await crypto.subtle.digest("SHA-256", a);
  return k(new Uint8Array(c), !0);
}, L = async (e, s, i) => {
  try {
    if (!e)
      return [new Error("Flow not found"), null];
    const a = e.selectedScopes.join(" ");
    if (e.type === "clientCredentials" || e.type === "password")
      return f(
        e,
        a,
        {
          proxyUrl: i
        },
        s
      );
    const c = (Math.random() + 1).toString(36).substring(2, 10), h = x(e.authorizationUrl, w(s)), t = new URL(h);
    let g = null;
    if (e.type === "implicit")
      t.searchParams.set("response_type", "token");
    else if (e.type === "authorizationCode" && (t.searchParams.set("response_type", "code"), e["x-usePkce"] !== "no")) {
      const r = C(), n = await T(r, e["x-usePkce"]);
      g = {
        codeVerifier: r,
        codeChallenge: n,
        codeChallengeMethod: e["x-usePkce"] === "SHA-256" ? "S256" : "plain"
      }, t.searchParams.set("code_challenge", n), t.searchParams.set("code_challenge_method", g.codeChallengeMethod);
    }
    if (e["x-scalar-redirect-uri"].startsWith("/")) {
      const r = S(s) || window.location.origin + window.location.pathname, n = x(e["x-scalar-redirect-uri"], { baseUrl: r });
      t.searchParams.set("redirect_uri", n);
    } else
      t.searchParams.set("redirect_uri", e["x-scalar-redirect-uri"]);
    e["x-scalar-security-query"] && Object.keys(e["x-scalar-security-query"]).forEach((r) => {
      const n = e["x-scalar-security-query"]?.[r];
      n && t.searchParams.set(r, n);
    }), t.searchParams.set("client_id", e["x-scalar-client-id"]), t.searchParams.set("state", c), a && t.searchParams.set("scope", a);
    const o = window.open(t, "openAuth2Window", "left=100,top=100,width=800,height=600");
    return o ? new Promise((r) => {
      const n = setInterval(() => {
        let p = null, d = null, u = null, y = null;
        try {
          const l = new URL(o.location.href).searchParams, P = e["x-tokenName"] || "access_token";
          p = l.get(P), d = l.get("code"), u = l.get("error"), y = l.get("error_description");
          const _ = new URLSearchParams(o.location.href.split("#")[1]);
          p ||= _.get(P), d ||= _.get("code"), u ||= _.get("error"), y ||= _.get("error_description");
        } catch {
        }
        if (o.closed || p || d || u)
          if (clearInterval(n), o.close(), u)
            r([new Error(`OAuth error: ${u}${y ? ` (${y})` : ""}`), null]);
          else if (p) {
            const l = o.location.href.match(/state=([^&]*)/)?.[1];
            r(l === c ? [null, p] : [new Error("State mismatch"), null]);
          } else d ? new URL(o.location.href).searchParams.get("state") === c ? f(
            e,
            a,
            {
              code: d,
              pkce: g,
              proxyUrl: i
            },
            s
          ).then(r) : r([new Error("State mismatch"), null]) : (clearInterval(n), r([new Error("Window was closed without granting authorization"), null]));
      }, 200);
    }) : [new Error("Failed to open auth window"), null];
  } catch {
    return [new Error("Failed to authorize oauth2 flow"), null];
  }
}, f = async (e, s, {
  code: i,
  pkce: a,
  proxyUrl: c
} = {}, h) => {
  if (!e)
    return [new Error("OAuth2 flow was not defined"), null];
  const t = new URLSearchParams();
  t.set("client_id", e["x-scalar-client-id"]), s && (e.type === "clientCredentials" || e.type === "password") && t.set("scope", s), e.clientSecret && (!e["x-scalar-credentials-location"] || e["x-scalar-credentials-location"] === "body") && t.set("client_secret", e.clientSecret), "x-scalar-redirect-uri" in e && e["x-scalar-redirect-uri"] && t.set("redirect_uri", e["x-scalar-redirect-uri"]), i ? (t.set("code", i), t.set("grant_type", "authorization_code"), a && t.set("code_verifier", a.codeVerifier)) : e.type === "password" ? (t.set("grant_type", "password"), t.set("username", e.username), t.set("password", e.password)) : t.set("grant_type", "client_credentials"), e["x-scalar-security-body"] && Object.entries(e["x-scalar-security-body"]).forEach(([m, o]) => {
    o && t.set(m, o);
  });
  try {
    const m = {
      "Content-Type": "application/x-www-form-urlencoded"
    };
    e.clientSecret && (!e["x-scalar-credentials-location"] || e["x-scalar-credentials-location"] === "header") && (m.Authorization = `Basic ${E(`${e["x-scalar-client-id"]}:${e.clientSecret}`)}`);
    const r = x(e.tokenUrl, w(h)), n = A(c, r) ? `${c}?${new URLSearchParams([["scalar_url", r]]).toString()}` : r, d = await (await fetch(n, {
      method: "POST",
      headers: m,
      body: t
    })).json(), u = e["x-tokenName"] || "access_token";
    return [null, d[u]];
  } catch {
    return [new Error("Failed to get an access token. Please check your credentials."), null];
  }
};
export {
  L as authorizeOauth2,
  f as authorizeServers,
  T as generateCodeChallenge,
  S as getInterpolatedServerUrl
};
