import { useState as M } from "react";
import { useCreation as N, useMemoizedFn as c, useInterval as se } from "ahooks";
import { joinURL as O, withQuery as te } from "ufo";
import T from "js-cookie";
import { setVisitorId as ie, getCookieOptions as ce } from "@arcblock/ux/lib/Util";
import fe from "jwt-decode";
import le from "@arcblock/ux/lib/Toast";
import ue from "p-retry";
import ae from "lodash/noop";
import { ReactGA as de } from "@arcblock/ux/lib/withTracker";
import { GA_LAST_SOURCE_PROVIDER as ke } from "@arcblock/ux/lib/withTracker/constant";
import Te from "../../Service/index.js";
import { createAxios as he, debugTmp as C, getBrowserLang as me, logger as b, debug as u, sleep as pe, debugTmpInterval as z, decrypt as Re } from "../../utils.js";
import { CHECK_INTERVAL_TIME as h, LANG_COOKIE_NAME as ye } from "../../constant.js";
class m extends Error {
}
const ve = 10, p = (e) => Re(e, localStorage.getItem("__encKey"), localStorage.getItem("__decKey"));
function qe({
  state: e,
  pageState: i,
  serviceHost: R,
  sessionTokenStorage: V,
  csrfTokenStorage: P,
  refreshTokenStorage: q,
  lazyRefreshToken: j,
  apiOptions: B = {},
  onRefresh: $ = ae
}) {
  const [D, y] = M(0), [Q, d] = M(h), { getToken: v, setToken: g, removeToken: X } = V, { setToken: Y } = P, { getToken: w, setToken: S, removeToken: J } = q, W = N(() => he({
    baseURL: R,
    timeout: 10 * 1e3,
    secure: !0
  }), [R]), k = () => {
    C("[removeToken] useSessionToken -> removeToken"), X(), J();
  }, _ = N(() => Te(
    {
      sessionTokenStorage: V,
      refreshTokenStorage: q,
      serviceHost: R,
      authServicePrefix: i.prefix,
      onRefreshTokenError() {
        C("[removeToken] useSessionToken -> createService: onRefreshTokenError"), k(), e.user && (e.user = null);
      }
    },
    B
  ), [R, i.prefix]), I = () => {
    const r = ce({ returnDomain: !1 });
    T.remove("connected_did", r), T.remove("connected_pk", r), T.remove("connected_app", r), T.remove("connected_wallet_os", r), z("[removeToken] clearSession-interval"), k();
  }, Z = c(() => {
    const r = T.get(ye) || me();
    r !== i.currentLocale && (i.currentLocale = r);
  }), H = c(async () => {
    const r = () => _.get(O(i.notificationPrefix, "/unread-count"));
    try {
      const { data: n } = await r();
      return n.unReadCount;
    } catch (n) {
      return console.error("getUnreadCount error", n), 0;
    }
  }), F = c(
    async ({ showProgress: r = !1, requestFn: n = null, onlyRefreshToken: t = !1, type: s = "refreshToken" }) => {
      try {
        if (e.loading)
          return console.warn("SessionProvider.refresh is currently in progress, call it will be noop"), { loading: !0 };
        r && (e.loading = !0);
        const { data: o, status: f } = await n(), a = o?.user?.did;
        if (a && de.set({
          user_id: a
        }), o?.user?.sourceProvider && localStorage.setItem(ke, o.user.sourceProvider), f === 400 && (C("[removeToken] useSessionToken -> _refresh: status 400"), k(), e.user = null, e.error = ""), o.error)
          throw e.error = o.error, e.open = !1, e.unReadCount = 0, new Error(o.error);
        if (o.user) {
          try {
            const l = await H();
            e.unReadCount = l || 0;
          } catch (l) {
            b.error("getUnreadCount error", l), e.unReadCount = 0;
          }
          o.nextToken && (g(o.nextToken), $({
            type: s,
            sessionToken: o.nextToken,
            refreshToken: o.nextRefreshToken,
            user: o.user
          }), o.nextRefreshToken && S(o.nextRefreshToken)), t || (e.open = !1, e.user = o.user, e.provider = o.provider, e.walletOS = o.walletOS), v() || le.error("Can't write session token, please use https url to access this page");
        } else
          throw r && (e.loading = i.autoConnect), e.open = i.autoConnect, e.user = null, e.provider = "", e.walletOS = "", e.unReadCount = 0, new m("Invalid token");
        return { data: o, status: f };
      } catch (o) {
        throw b.error("SessionProvider.refresh error", o), e.open = !1, e.error = o.message, o?.response?.status === 400 ? new m("Invalid token") : o;
      } finally {
        r && (e.loading = !1);
      }
    }
  ), x = c(async (r = !1, n = !1) => {
    u("handleRefreshToken", { showProgress: r, onlyRefreshToken: n });
    const t = () => W.post(te(O(i.prefix, "/refreshSession")), null, {
      headers: {
        authorization: `Bearer ${encodeURIComponent(w())}`
      }
    });
    d(void 0);
    try {
      await F({ showProgress: r, requestFn: t, onlyRefreshToken: n, type: "refreshToken" }), y(0), d(h);
    } catch (s) {
      s instanceof m ? (console.warn("refresh token failed, remove all tokens"), y(0), C("[removeToken] useSessionToken -> handleRefreshToken: refresh token failed, remove all tokens"), k(), d(h)) : (b.error("refresh token failed, unexpected error:", s), y(D + 1), await pe(h), D >= ve ? (y(0), d(void 0)) : d(h));
    }
  }), G = c((r = !1) => {
    if (j)
      return;
    const n = v();
    let t = r;
    const s = (/* @__PURE__ */ new Date()).getTime();
    if (n)
      try {
        const { exp: o, iat: f } = fe(n);
        o * 1e3 - s < s - f * 1e3 && (t = !0);
      } catch {
        t = !0;
      }
    else
      t = !0;
    t && (w() ? x(!1, !0) : (z("[clearSession-interval] useSessionToken -> checkToken: empty refreshToken"), I(), e.user && (e.user = null)));
  }), K = c(async ({ showProgress: r = !1, forceRefreshToken: n = !1 } = {}) => {
    const t = () => ue(() => _.get(O(i.prefix, "/session"), { secure: !0 }), {
      retries: 2
    });
    u("handleRefreshUser", { showProgress: r, forceRefreshToken: n });
    try {
      if (n)
        throw new m("need force refresh token");
      await F({ showProgress: r, requestFn: t, type: "refreshUser" });
    } catch (s) {
      s instanceof m && (u("handleRefreshUser failed, try to refresh token", { err: s }), await x());
    }
  }), ee = c(async () => {
    const r = v(), n = w();
    e.user || (r || n ? await K() : (u("[clearSession] syncSessionSate: empty sessionToken and refreshToken"), I(), e.user && (e.user = null)));
  }), re = c(() => {
    if (e.initialized && e.user)
      try {
        G();
      } catch {
      }
  }), oe = c((r) => {
    const n = Array.isArray(r) ? r[0] : r;
    u("handleLoginResult", { loginResult: n, result: r });
    const { loginToken: t, csrfToken: s, sessionToken: o, refreshToken: f, visitorId: a, encrypted: l = !0 } = n, L = t || o;
    let E, U, A;
    if (L) {
      if (E = l ? p(L) : L, u("handleLoginResult: setSessionToken", { decryptSessionToken: E }), g(E), s) {
        const ne = l ? p(s) : s;
        Y(ne);
      }
      f && (U = l ? p(f) : f, u("handleLoginResult: setRefreshToken", { decryptRefreshToken: U }), S(U));
    }
    a && (A = l ? p(a) : a, u("handleLoginResult: setVisitorId", { decryptVisitorId: A }), ie(A));
  });
  return se(
    () => {
      Z(), G();
    },
    Q,
    { immediate: !0 }
  ), {
    renewToken: re,
    handleRefreshUser: K,
    handleRefreshToken: x,
    syncSessionSate: ee,
    handleLoginResult: oe,
    decrypt: p,
    removeToken: k,
    clearSession: I,
    getSessionToken: v,
    getRefreshToken: w,
    setRefreshToken: S,
    setSessionToken: g,
    service: _
  };
}
export {
  qe as default
};
