import { useEffect, useSyncExternalStore } from "react";
import { proBilling } from "../../platform/pro-billing.js";
import { proApi } from "./pro-api.js";

const INITIAL = Object.freeze({ tier: "free", maxAccounts: 1, connection: "loading", busy: false, outcome: null });

export function createProEntitlementController({ api = proApi, billing = proBilling, hashChallenge = sha256 } = {}) {
  let state = INITIAL;
  const listeners = new Set();
  const publish = (patch) => { state = { ...state, ...patch }; for (const listener of listeners) listener(); };
  async function refresh() {
    try { const value = await api.status(); publish({ ...value, connection: "ready" }); }
    catch { publish({ connection: "unavailable" }); }
    return state;
  }
  async function bind(method, retry = true) {
    publish({ busy: true, outcome: null });
    try {
      const challenge = await api.challenge();
      const challengeHash = challenge.challengeHash ?? await hashChallenge(challenge.challenge);
      const result = await billing[method]({ backendKeyThumbprint: challenge.backendKeyThumbprint, challengeHash });
      if (result.state !== "activated") { publish({ busy: false, outcome: result.state }); return result; }
      try { await api.activate(challenge.challenge, result.certificate); }
      catch (error) {
        if (retry && error?.message === "entitlement_challenge_expired") return bind("restore", false);
        throw error;
      }
      await refresh();
      publish({ busy: false, outcome: "activated" });
      return { state: "activated" };
    } catch { publish({ busy: false, outcome: "unavailable" }); return { state: "unavailable" }; }
  }
  return {
    getState: () => state,
    subscribe(listener) { listeners.add(listener); return () => listeners.delete(listener); },
    refresh,
    purchase: () => bind("purchase"),
    restore: () => bind("restore"),
    getProduct: () => billing.getProduct(),
    openManagement: () => billing.openManagement?.(),
  };
}

const defaultController = createProEntitlementController();

export function useProEntitlement(controller = defaultController) {
  const state = useSyncExternalStore(controller.subscribe, controller.getState, controller.getState);
  useEffect(() => { controller.refresh(); }, [controller]);
  return { ...state, refresh: controller.refresh, purchase: controller.purchase, restore: controller.restore, getProduct: controller.getProduct, openManagement: controller.openManagement };
}

async function sha256(value) {
  const bytes = new TextEncoder().encode(value);
  const digest = await crypto.subtle.digest("SHA-256", bytes);
  return btoa(String.fromCharCode(...new Uint8Array(digest))).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
}
