'use client';
import { useCallback, useRef, useState } from 'react';
import { HONEYPOT_FIELD, ELAPSED_MS_FIELD, type HumanitySignals } from '../utils/humanity-signals';
/**
* useHumanitySignals — client primitive backing the invisible bot-protection
* layer. Owns the honeypot ref + a mount timestamp, and exposes the
* props to render the field plus a getter that produces the wire object to
* merge into a form's POST body. Reused by every public form (contact,
* waitlist, ticket, review) so the signal shape lives in exactly one place.
*
* Usage:
* const { honeypotInputProps, getSignals, resetSignals } = useHumanitySignals()
* // render:
* // submit: fetch(url, { body: JSON.stringify({ ...formData, ...getSignals() }) })
* // after a successful submit: resetSignals()
*
* The two signals are origin-independent (they ride in the body), so they keep
* working when the form is embedded behind a reverse-proxy / prefixed URL.
*/
export function useHumanitySignals() {
const ref = useRef(null);
// performance.now() is monotonic (immune to wall-clock skew). SSR-guarded
// even though the hook only executes on the client.
//
// Sampled in a lazy `useState` initialiser, then copied into a ref. Not
// `useRef(performance.now())`: that argument is re-evaluated on EVERY render
// even though only the first call uses it, so the component would read the
// clock during render forever. And not state alone: `resetSignals` restarts
// the window after a successful submit, which through state would re-render
// the whole form for a value nothing renders.
const [mountedAt] = useState(() => (typeof performance !== 'undefined' ? performance.now() : 0));
const startedAtRef = useRef(mountedAt);
const getSignals = useCallback(
(): HumanitySignals => ({
[HONEYPOT_FIELD]: ref.current?.value ?? '',
[ELAPSED_MS_FIELD]: typeof performance !== 'undefined' ? Math.round(performance.now() - startedAtRef.current) : 0,
}),
[],
);
const resetSignals = useCallback(() => {
if (ref.current) ref.current.value = '';
if (typeof performance !== 'undefined') startedAtRef.current = performance.now();
}, []);
return { honeypotInputProps: { ref, name: HONEYPOT_FIELD }, getSignals, resetSignals } as const;
}