'use strict';

var React = require('react');

function _interopNamespace(e) {
  if (e && e.__esModule) return e;
  var n = Object.create(null);
  if (e) {
    Object.keys(e).forEach(function (k) {
      if (k !== 'default') {
        var d = Object.getOwnPropertyDescriptor(e, k);
        Object.defineProperty(n, k, d.get ? d : {
          enumerable: true,
          get: function () { return e[k]; }
        });
      }
    });
  }
  n.default = e;
  return Object.freeze(n);
}

var React__namespace = /*#__PURE__*/_interopNamespace(React);

// src/react.ts

// src/firestore-compat.ts
function toDbQuery(constraints) {
  const whereFilters = [];
  let orderByClause;
  let limitValue;
  for (const c of constraints) {
    if (c.__constraint === "where") {
      const w = c;
      whereFilters.push({ field: w.field, op: normalizeOp(w.op), value: w.value });
    } else if (c.__constraint === "orderBy") {
      const o = c;
      orderByClause = { field: o.field, direction: o.direction };
    } else if (c.__constraint === "limit") {
      limitValue = c.value;
    }
  }
  const out = {};
  if (whereFilters.length > 0) out.where = whereFilters;
  if (orderByClause) out.orderBy = orderByClause;
  if (limitValue !== void 0) out.limit = limitValue;
  return out;
}
function normalizeOp(op) {
  return op;
}

// src/react.ts
function CheckoutLink({
  client,
  productId,
  planId,
  callbackUrl,
  tenantType,
  tenantId,
  children,
  onIntentCreated,
  onError,
  noAutoRedirect,
  ...rest
}) {
  const [submitting, setSubmitting] = React__namespace.useState(false);
  const checkout = client.checkout;
  const handleClick = React__namespace.useCallback(
    async (event) => {
      event.preventDefault();
      if (submitting) return;
      if (!checkout || typeof checkout.start !== "function") {
        onError?.(new Error("SDK client missing `checkout` namespace. Upgrade @neetru/sdk to 1.1+."));
        return;
      }
      setSubmitting(true);
      try {
        const result = await checkout.start({
          productId,
          planId,
          callbackUrl,
          tenantType,
          tenantId,
          autoRedirect: !noAutoRedirect
        });
        onIntentCreated?.(result);
      } catch (err) {
        onError?.(err instanceof Error ? err : new Error(String(err)));
      } finally {
        setSubmitting(false);
      }
    },
    [submitting, checkout, productId, planId, callbackUrl, tenantType, tenantId, noAutoRedirect, onIntentCreated, onError]
  );
  return React__namespace.createElement(
    "a",
    {
      ...rest,
      href: rest.href ?? "#",
      onClick: handleClick,
      "aria-busy": submitting || void 0,
      "data-neetru-checkout-link": "true"
    },
    children
  );
}
var EntitlementContext = React__namespace.createContext({
  readonly: false
});
function useEntitlementContext() {
  return React__namespace.useContext(EntitlementContext);
}
function EntitlementGate({
  client,
  feature,
  productSlug,
  mode = "block",
  fallback,
  loading,
  children
}) {
  const [state, setState] = React__namespace.useState({
    status: "loading"
  });
  const resolvedSlug = productSlug ?? client.config.productId ?? "";
  const resolvedTenantId = client.config.tenantId;
  React__namespace.useEffect(() => {
    let cancelled = false;
    const run = async () => {
      try {
        let result2;
        const usage = client.usage;
        if (usage && typeof usage.check === "function" && resolvedTenantId) {
          const res = await usage.check(feature, {
            productId: resolvedSlug,
            tenantId: resolvedTenantId
          });
          result2 = {
            allowed: res.allowed === true,
            reason: res.reason,
            limit: res.limit,
            currentUsage: res.currentUsage,
            behavior: res.behavior
          };
        } else {
          const allowed2 = await client.entitlements.check(resolvedSlug, feature);
          result2 = { allowed: allowed2 };
        }
        if (!cancelled) setState({ status: "ready", result: result2 });
      } catch (err) {
        if (!cancelled) {
          setState({ status: "ready", result: { allowed: true, reason: "check_error_fallback" } });
        }
        if (typeof console !== "undefined") console.warn("[EntitlementGate] check failed \u2014 fail-open", err);
      }
    };
    run();
    return () => {
      cancelled = true;
    };
  }, [client, feature, resolvedSlug, resolvedTenantId]);
  if (state.status === "loading") {
    return React__namespace.createElement(React__namespace.Fragment, null, loading ?? null);
  }
  const result = state.result;
  const allowed = result?.allowed === true;
  const isReadonly = !allowed && (mode === "readonly" || result?.behavior === "readonly");
  if (!allowed && mode === "block" && !isReadonly) {
    return React__namespace.createElement(React__namespace.Fragment, null, fallback ?? null);
  }
  return React__namespace.createElement(
    EntitlementContext.Provider,
    {
      value: {
        readonly: isReadonly,
        reason: result?.reason,
        limit: result?.limit,
        currentUsage: result?.currentUsage
      }
    },
    children
  );
}
var DEFAULT_INTERVAL_MS = 5e3;
function isDocumentHidden() {
  return typeof document !== "undefined" && document.hidden === true;
}
function serializeSource(source) {
  if (!source) return null;
  if (source.__kind === "collection") {
    return `collection:${source.id}`;
  }
  const dbQuery = toDbQuery(source.constraints);
  return `query:${source.collection}:${JSON.stringify(dbQuery)}`;
}
function rowsFromList(snap) {
  return snap.docs.map((d) => {
    const data = d.data;
    const { id: _omit, ...rest } = data;
    return { ...rest, id: d.id };
  });
}
function rowFromGet(snap, id) {
  const first = snap?.docs[0];
  if (!first) return null;
  const data = first.data;
  const { id: _omit, ...rest } = data;
  return { ...rest, id };
}
function useCollection(source, options) {
  const intervalMs = options?.intervalMs ?? DEFAULT_INTERVAL_MS;
  const poll = options?.poll ?? false;
  const sourceKey = serializeSource(
    source
  );
  const [state, setState] = React__namespace.useState({
    data: null,
    isLoading: sourceKey !== null,
    error: null,
    isStale: false,
    lastUpdated: null
  });
  const mountedRef = React__namespace.useRef(true);
  const sourceRef = React__namespace.useRef(source);
  sourceRef.current = source;
  React__namespace.useEffect(() => {
    mountedRef.current = true;
    const current = sourceRef.current;
    if (!current || sourceKey === null) {
      setState({ data: null, isLoading: false, error: null, isStale: false, lastUpdated: null });
      return () => {
        mountedRef.current = false;
      };
    }
    setState((prev) => ({ ...prev, isLoading: prev.data === null }));
    const collectionName = current.__kind === "query" ? current.collection : current.id;
    const dbQuery = current.__kind === "query" ? toDbQuery(current.constraints) : void 0;
    const col = current.db.collection(collectionName);
    const applySnap = (snap) => {
      if (!mountedRef.current) return;
      setState({
        data: rowsFromList(snap),
        isLoading: false,
        error: null,
        isStale: snap.stale === true,
        lastUpdated: Date.now()
      });
    };
    const applyError = (e) => {
      if (!mountedRef.current) return;
      setState((prev) => ({
        ...prev,
        // Mantém o último data bom — não limpa em erro de refresh.
        isLoading: false,
        error: e instanceof Error ? e : new Error(String(e)),
        isStale: true
      }));
    };
    if (poll) {
      let cancelled = false;
      const fetchOnce = async () => {
        if (cancelled || isDocumentHidden()) return;
        try {
          const snap = await col.list(dbQuery);
          if (!cancelled) applySnap(snap);
        } catch (e) {
          if (!cancelled) applyError(e);
        }
      };
      void fetchOnce();
      const timer = setInterval(fetchOnce, intervalMs);
      return () => {
        cancelled = true;
        clearInterval(timer);
        mountedRef.current = false;
      };
    }
    let unsub;
    try {
      unsub = col.onSnapshot(dbQuery, applySnap);
    } catch (e) {
      applyError(e);
    }
    return () => {
      mountedRef.current = false;
      unsub?.();
    };
  }, [sourceKey, intervalMs, poll]);
  return state;
}
function useDoc(ref, options) {
  const intervalMs = options?.intervalMs ?? DEFAULT_INTERVAL_MS;
  const poll = options?.poll ?? false;
  const refKey = ref && ref.id ? `${ref.collection}/${ref.id}` : null;
  const [state, setState] = React__namespace.useState({
    data: null,
    isLoading: refKey !== null,
    error: null,
    isStale: false,
    lastUpdated: null
  });
  const mountedRef = React__namespace.useRef(true);
  const refRef = React__namespace.useRef(ref);
  refRef.current = ref;
  React__namespace.useEffect(() => {
    mountedRef.current = true;
    const current = refRef.current;
    if (!current || refKey === null) {
      setState({ data: null, isLoading: false, error: null, isStale: false, lastUpdated: null });
      return () => {
        mountedRef.current = false;
      };
    }
    setState((prev) => ({ ...prev, isLoading: prev.data === null }));
    const docRef = current.db.collection(current.collection).doc(current.id);
    const id = current.id;
    const applySnap = (snap) => {
      if (!mountedRef.current) return;
      setState({
        data: rowFromGet(snap, id),
        isLoading: false,
        error: null,
        isStale: snap?.stale === true,
        lastUpdated: Date.now()
      });
    };
    const applyError = (e) => {
      if (!mountedRef.current) return;
      setState((prev) => ({
        ...prev,
        isLoading: false,
        error: e instanceof Error ? e : new Error(String(e)),
        isStale: true
      }));
    };
    if (poll) {
      let cancelled = false;
      const fetchOnce = async () => {
        if (cancelled || isDocumentHidden()) return;
        try {
          const snap = await docRef.get();
          if (!cancelled) applySnap(snap);
        } catch (e) {
          if (!cancelled) applyError(e);
        }
      };
      void fetchOnce();
      const timer = setInterval(fetchOnce, intervalMs);
      return () => {
        cancelled = true;
        clearInterval(timer);
        mountedRef.current = false;
      };
    }
    let unsub;
    try {
      unsub = docRef.onSnapshot(applySnap);
    } catch (e) {
      applyError(e);
    }
    return () => {
      mountedRef.current = false;
      unsub?.();
    };
  }, [refKey, intervalMs, poll]);
  return state;
}
function resolveAuth(input) {
  const maybe = input;
  if (maybe.auth && typeof maybe.auth.onAuthStateChanged === "function") {
    return maybe.auth;
  }
  return input;
}
function useUser(input, options) {
  const timeoutMs = options?.timeoutMs ?? 8e3;
  const auth = resolveAuth(input);
  const [state, setState] = React__namespace.useState(() => {
    let seeded = null;
    try {
      seeded = auth.getUser();
    } catch {
      seeded = null;
    }
    return { user: seeded, isLoading: seeded === null, error: null };
  });
  const mountedRef = React__namespace.useRef(true);
  React__namespace.useEffect(() => {
    mountedRef.current = true;
    let settled = false;
    const timer = setTimeout(() => {
      if (!mountedRef.current || settled) return;
      setState((prev) => prev.isLoading ? { ...prev, isLoading: false } : prev);
    }, timeoutMs);
    let unsub;
    try {
      unsub = auth.onAuthStateChanged((user) => {
        if (!mountedRef.current) return;
        settled = true;
        setState({ user: user ?? null, isLoading: false, error: null });
      });
    } catch (e) {
      if (mountedRef.current) {
        setState({
          user: null,
          isLoading: false,
          error: e instanceof Error ? e : new Error(String(e))
        });
      }
    }
    return () => {
      mountedRef.current = false;
      clearTimeout(timer);
      unsub?.();
    };
  }, [auth, timeoutMs]);
  return state;
}

exports.CheckoutLink = CheckoutLink;
exports.EntitlementGate = EntitlementGate;
exports.useCollection = useCollection;
exports.useDoc = useDoc;
exports.useEntitlementContext = useEntitlementContext;
exports.useUser = useUser;
//# sourceMappingURL=react.cjs.map
//# sourceMappingURL=react.cjs.map