var _useState_OB  = React.useState;
var _useEffect_OB = React.useEffect;
var _useRef_OB    = React.useRef;

/**
 * OnboardingOverlay — the first-run profile question ("Variant A"), ported from
 * prototype/onboarding/index.html's renderVariantA.
 *
 * Spec: architecture/ONBOARDING-PROFILE-MIGRATION-PLAN.md §4. One screen, two
 * bio cards; the work card discloses the occupation chips inline, and "Something
 * else" reveals a free-text field. Answering shows the result card with the
 * recommended plan; its "Start scanning" button is a pure dismiss.
 *
 * Mounted by AnalysisPage inside the `idle` phase and rendered OVER the idle
 * content (plan §3), so the camera UI is already behind it and dismissing the
 * overlay needs no navigation and no second load. It never blocks a scan: every
 * exit path (answer, skip link, Escape) writes the profile and unmounts.
 *
 * Props:
 *   onDone   (func) — called after the profile is written and the user is
 *                     finished with the sheet. The parent unmounts the overlay.
 *
 * Persistence is UserProfileStore only — the prototype's localStorage key is
 * gone. Tier labels, prices and the recommendation all come from Tiers.jsx; this
 * file composes no plan claims of its own.
 *
 * Written in ES5 for Babel 6 compatibility. File-local helpers and constants use
 * the `ob` namespace prefix (CLAUDE.md: every top-level var is a window global).
 */

/**
 * obCopy — every user-visible string in the overlay, in one block.
 *
 * NOTE (2026-09-18): the migration plan §4 lists the heading as "Where are you
 * scanning?" with cards "My home — I live here" / "Somewhere I work — clients,
 * sites, samples". Those strings are Variant B's (prototype line 574), not
 * Variant A's. The strings below are Variant A's as the prototype actually reads
 * it today, which is the component this file ports and the one Rozario chose;
 * the §4 disclosure label "What is your occupation?" is Variant A's and is used
 * verbatim. If the B-style heading was the intent, it is one edit here.
 */
var obCopy = {
    heading:        'How would you like to use Mould Detect?',
    subheading:     'You will only see this onboarding section once, which helps us personalise the extensive features of Mould Detect. Change any time from the menu, under Your setup.',
    homeTitle:      'I’m checking my own place',
    homeHint:       'Home, unit or rental I live in · Free',
    workTitle:      'I will use Mould Detect for clients or work activities',
    workHint:       'Trades, inspections, remediation, labs',
    roleLabel:      'What is your occupation?',
    roleOtherLabel: 'Tell us a little about your role',
    roleOtherHint:  'A few words is plenty. It helps us suggest the right tools.',
    roleOtherPlaceholder: 'e.g. Property manager, strata, insurer',
    cta:            'Start scanning',
    skip:           'Just exploring',
    resultHeading:  'You’re set',
    resultStrap:    'Start free, upgrade any time',
    resultFooter:   'You can change this any time from the menu, under Your setup',
    startCta:       'Start scanning'
};

/**
 * obRoleChips — the occupation chips (UI copy, so they live with the overlay and
 * not in Tiers.jsx). `role` is the persisted enum value (§5.2); two chips share
 * the `remediator` role deliberately — "Mould remediator" and "Building
 * remediator" are the same tier and the same stored role, so each chip carries
 * its own `id` for pressed state. The tier each one implies is NOT stored here:
 * obRecommendTier(cohort, role) in Tiers.jsx owns that mapping.
 */
var obRoleChips = [
    { id: 'cleaner',            label: 'Cleaner',               role: 'cleaner' },
    { id: 'plumber',            label: 'Plumber',               role: 'plumber' },
    { id: 'inspector',          label: 'Building inspector',    role: 'inspector' },
    { id: 'mould_remediator',   label: 'Mould remediator',      role: 'remediator' },
    { id: 'building_remediator',label: 'Building remediator',   role: 'remediator' },
    { id: 'franchise',          label: 'Franchise',             role: 'franchise' },
    { id: 'hygienist',          label: 'Occupational hygienist',role: 'hygienist' },
    { id: 'lab',                label: 'Lab',                   role: 'lab' },
    { id: 'university',         label: 'University',            role: 'university' },
    { id: 'other',              label: 'Something else',        role: 'other' }
];

// The roleDetail cap is OB_ROLE_DETAIL_MAX, owned by UserProfileStore.jsx (the
// file that persists the field). This file used to carry a second constant of
// its own with the same value; two constants for one rule is one that can drift.
// UserProfileStore loads before this file (index.html dependency order), so the
// global is always defined by the time anything here reads it.

/**
 * obProfileLabel — the ONE derivation of "what the user told us", shared by the
 * result card's eyebrow and the dashboard's "Your setup" chip (review F6).
 *
 * Order of preference: the free-text role (only when the role IS 'other' — the
 * words the user typed beat any label we could pick), then the occupation chip's
 * label, then the cohort label from Tiers. Never the tier: the pill, the price
 * line and the chip's own suffix already carry that.
 *
 * `maxLen` (optional) truncates with an ellipsis; the chip passes 24 because it
 * is a one-line pill, the result card passes nothing.
 */
var obProfileLabel = function (onboarding, maxLen) {
    var ob = onboarding || {};
    if (ob.role === 'other' && ob.roleDetail) {
        return (maxLen && ob.roleDetail.length > maxLen)
            ? ob.roleDetail.slice(0, maxLen) + '…'
            : ob.roleDetail;
    }
    if (ob.role) {
        for (var i = 0; i < obRoleChips.length; i++) {
            if (obRoleChips[i].role === ob.role) return obRoleChips[i].label;
        }
    }
    return Tiers.cohortLabel(ob.cohort);
};

/** obIcon — a Material Symbols ligature span. Every name used in this file is in
 *  assets/fonts/symbols.icons.txt (home, engineering, add_a_photo, check_circle,
 *  check, person, eco):
 *  the font is a subset, so an unlisted name would render as literal text. */
var obIcon = function (name, className) {
    return React.createElement(
        'span',
        { className: 'material-symbols-outlined ' + (className || ''), 'aria-hidden': 'true' },
        name
    );
};

/**
 * obSelMark — the selected-state badge for an option card: a filled primary
 * circle with a forest check when selected, an empty white/40 ring when not.
 * The SHAPE changes, not just the colour (DESIGN.md: never colour alone).
 * Decorative: the card's aria-pressed carries the state for assistive tech.
 */
var obSelMark = function (selected) {
    return (
        <span
            aria-hidden="true"
            className={'absolute top-3 right-3 w-6 h-6 rounded-full flex items-center justify-center ' +
                (selected ? 'bg-primary' : 'ring-2 ring-white/40')}
        >
            {selected && obIcon('check', 'text-forest text-base font-bold')}
        </span>
    );
};

/**
 * OnboardingResultCard — "You're set": the recommended plan, what it unlocks and
 * the dismiss CTA. Homeowners additionally get the single Essential step-up line
 * (§10 decision 2) — the only place Essential enters the flow, and it costs no
 * extra question.
 */
var obEyebrow = function (props) {
    // Untruncated: the card has the room, and the free text is the answer.
    return obProfileLabel({ role: props.role, roleDetail: props.roleDetail, cohort: props.cohort });
};

var OnboardingResultCard = function (props) {
    var tier = Tiers.get(props.recommendedTier);
    var unlocks = Tiers.unlocks(props.recommendedTier);
    var stepUpId = Tiers.stepUpFor(props.recommendedTier);
    var stepUp = stepUpId ? Tiers.get(stepUpId) : null;

    return (
        // Renders straight onto the overlay's dark promo fill (DESIGN.md §2
        // Surfaces): white / accent / primary text only. Ratios are against
        // forest #1a4332, the LIGHTER end of the gradient (the worst case).
        <div className="ob-result-enter">
            {/* Eyebrow names what the user told us (occupation, or the free-text
                role, or the cohort) — never the tier, which the pill and the
                price line already carry. Primary on forest 4.55:1. */}
            <p className="flex items-center gap-1.5 text-[10px] font-black text-primary uppercase tracking-widest mb-2">
                {obIcon('person', 'text-base')}
                <span>{obEyebrow(props)}</span>
            </p>
            <div className="flex items-center justify-between gap-3 mb-3">
                <h3 id="ob-heading" tabIndex={-1} ref={props.headingRef} className="font-display font-extrabold text-xl text-white outline-none">
                    {obCopy.resultHeading}
                </h3>
                {/* pillClass is owned by Tiers.jsx and written for light
                    surfaces; the white/40 ring keeps a bg-forest pill
                    (Enterprise) visible on the forest panel (3.16:1). */}
                <span className={'text-[10px] font-black uppercase tracking-widest px-2.5 py-1 rounded-full shrink-0 ring-1 ring-white/40 ' + tier.pillClass}>
                    {tier.label}
                </span>
            </div>

            <p className="text-base font-extrabold text-white mb-1">{tier.label} · {tier.priceLine}</p>
            <p className="text-sm font-medium text-accent mb-4">{obCopy.resultStrap}</p>

            <ul className="space-y-2 mb-5">
                {unlocks.map(function (line) {
                    return (
                        <li key={line} className="flex items-center gap-2.5 text-sm font-semibold text-accent">
                            {obIcon('check_circle', 'text-primary text-base shrink-0')}
                            {line}
                        </li>
                    );
                })}
            </ul>

            {/* Essential step-up — homeowners only (recommendedTier 'free').
                White on primary/15-over-forest 8.72:1. */}
            {stepUp && (
                <p className="text-sm font-bold text-white bg-primary/15 ring-1 ring-primary/50 rounded-lg px-3 py-2.5 mb-5 leading-relaxed">
                    Save your history and reports from {stepUp.priceDisplay}/mo
                </p>
            )}

            {/* Forest on primary 4.55:1 — white on primary is 2.44:1 and fails
                AA at this size, so this deliberately differs from UpgradePanel. */}
            <button
                type="button"
                onClick={props.onStart}
                className="w-full min-h-[48px] bg-primary text-forest font-extrabold py-3 rounded-full flex items-center justify-center gap-2 btn-nature hover:brightness-110 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-forest outline-none text-sm"
            >
                {obIcon('add_a_photo', 'text-base')}
                {obCopy.startCta}
            </button>

            <p className="text-center text-xs font-semibold text-accent mt-3">{obCopy.resultFooter}</p>
        </div>
    );
};

var OnboardingOverlay = function (props) {
    var profileStore = useUserProfile();

    // --- Controlled state (the prototype's state.variantState.A) ---
    var selectedState = _useState_OB(null);          // 'home' | 'work' | null
    var selected = selectedState[0];
    var setSelected = selectedState[1];

    var chipState = _useState_OB(null);              // chip id, e.g. 'mould_remediator'
    var chipId = chipState[0];
    var setChipId = chipState[1];

    var otherState = _useState_OB('');               // free text for "Something else"
    var roleOther = otherState[0];
    var setRoleOther = otherState[1];

    // The written answer — set once "Start scanning" commits, and what the result
    // card renders from. Null while the question is still open.
    var answerState = _useState_OB(null);
    var answer = answerState[0];
    var setAnswer = answerState[1];

    var headingRef = _useRef_OB(null);
    // The dialog element itself, so Escape can be scoped to focus INSIDE the
    // sheet (review F9). See the keydown effect below.
    var sheetRef = _useRef_OB(null);
    var onDone = props.onDone || function () {};

    var chip = null;
    for (var i = 0; i < obRoleChips.length; i++) {
        if (obRoleChips[i].id === chipId) chip = obRoleChips[i];
    }

    var homeSelected = selected === 'home';
    var workSelected = selected === 'work';
    var otherNeedsText = !!(chip && chip.role === 'other');
    var ctaEnabled = homeSelected ||
        (workSelected && !!chip && (!otherNeedsText || roleOther.replace(/^\s+|\s+$/g, '').length > 0));

    // Focus the heading when the sheet opens (and again when the result card
    // replaces the question, since that heading is a different node).
    _useEffect_OB(function () {
        if (headingRef.current && headingRef.current.focus) headingRef.current.focus();
    }, [answer === null]);

    /**
     * "Just exploring" (and Escape).
     *
     * On the FIRST run this records the skip, which is what stops the overlay
     * re-prompting. On a REOPEN from the header menu's "Your setup" it writes
     * nothing: the user already told us who they are, and backing out of an edit
     * must not erase that answer.
     */
    var handleSkip = function () {
        if (!profileStore.isOnboarded) profileStore.skipOnboarding('onboarding-A');
        profileStore.closeOnboarding();
        onDone();
    };

    var handleStart = function () {
        if (!ctaEnabled) return;
        var written;
        if (homeSelected) {
            written = profileStore.completeOnboarding({
                cohort: 'homeowner',
                context: 'my_home',
                role: null,
                roleDetail: null,
                source: 'onboarding-A'
            });
        } else {
            // The cohort mirrors the tier the occupation implies (business /
            // professional / enterprise) — Tiers.jsx owns that mapping, this
            // component never hard-codes a tier.
            var role = chip.role;
            var cohort = Tiers.ROLE_TIER[role] || 'business';
            written = profileStore.completeOnboarding({
                cohort: cohort,
                context: 'client_property',
                role: role,
                roleDetail: (role === 'other') ? roleOther : null,
                source: 'onboarding-A'
            });
        }
        setAnswer(written);
    };

    var handleFinish = function () {
        profileStore.closeOnboarding();
        onDone();
    };

    /**
     * Escape = "Just exploring" (plan §4). Bound on `document` because the sheet
     * is not always what holds focus, but acted on ONLY when focus is inside the
     * sheet (review F9).
     *
     * Why that matters: on a FIRST run Escape writes `skippedAt`, which is a real
     * answer and permanently stops the prompt. Bound document-wide, any other
     * Escape-dismissible thing on the page — a Clerk modal, a browser
     * autocomplete, a future popover — would silently spend the user's one
     * onboarding on their behalf. Focus is on the heading when the sheet opens,
     * so the intended path is unaffected.
     */
    _useEffect_OB(function () {
        var onKeyDown = function (e) {
            if (e.key !== 'Escape' && e.keyCode !== 27) return;
            var sheet = sheetRef.current;
            if (!sheet) return;
            var active = document.activeElement;
            var inside = !!active && (active === sheet ||
                (typeof sheet.contains === 'function' && sheet.contains(active)));
            if (!inside) return;
            e.stopPropagation();
            if (answer) { handleFinish(); } else { handleSkip(); }
        };
        document.addEventListener('keydown', onKeyDown);
        return function () { document.removeEventListener('keydown', onKeyDown); };
    }, [answer]);

    var handleSelect = function (choice) {
        setSelected(function (prev) { return prev === choice ? null : choice; });
        if (choice !== 'work') { setChipId(null); setRoleOther(''); }
    };

    var handleChip = function (c) {
        setChipId(c.id);
        if (c.role !== 'other') setRoleOther('');
    };

    return (
        // Dark promo panel (DESIGN.md §2 Surfaces — same treatment as
        // UpgradePanel). Legibility rule in reverse: on this fill only white,
        // accent and primary text; forest text only on primary or white fills.
        // Contrast ratios in the comments are against forest #1a4332, the
        // lighter (worst-case) end of the gradient.
        <div
            className="fixed inset-0 z-[100] flex items-start sm:items-center justify-center p-3 sm:p-6 bg-background-dark/70 backdrop-blur-sm"
            data-testid="onboarding-overlay"
        >
            <div
                ref={sheetRef}
                role="dialog"
                aria-modal="true"
                aria-labelledby="ob-heading"
                className="relative w-full max-w-md max-h-full flex flex-col rounded-xl overflow-hidden bg-gradient-to-br from-forest to-background-dark text-white shadow-clay"
            >
                {/* Badge watermark — decoration only, outside the scroller so it
                    can never cause horizontal overflow. */}
                <span className="material-symbols-outlined absolute -right-4 -bottom-4 text-[120px] leading-none opacity-5 pointer-events-none select-none" aria-hidden="true">eco</span>

                <div className="relative z-10 overflow-y-auto overscroll-contain" style={{ paddingBottom: 'env(safe-area-inset-bottom)' }}>
                {answer ? (
                    <div className="p-5">
                        <OnboardingResultCard
                            headingRef={headingRef}
                            cohort={answer.onboarding.cohort}
                            role={answer.onboarding.role}
                            roleDetail={answer.onboarding.roleDetail}
                            recommendedTier={answer.onboarding.recommendedTier}
                            onStart={handleFinish}
                        />
                    </div>
                ) : (
                    <div className="p-5">
                        {/* Skip lives at the top so the escape hatch is visible without
                            scrolling on short viewports (iPhone: the CTA already sits at
                            the fold). */}
                        <div className="flex items-start justify-between gap-2 mb-2">
                            <h2
                                id="ob-heading"
                                tabIndex={-1}
                                ref={headingRef}
                                className="font-display font-extrabold text-xl leading-tight text-white outline-none pt-1.5"
                            >
                                {obCopy.heading}
                            </h2>
                            {/* Subtle secondary link: accent on forest 7.17:1; 44px
                                target via min-h + padding, pulled back into the corner. */}
                            <button
                                type="button"
                                onClick={handleSkip}
                                className="shrink-0 -mr-2 -mt-1 px-2 min-h-[44px] rounded-lg text-xs font-bold text-accent underline underline-offset-2 hover:text-white btn-nature focus-visible:ring-2 focus-visible:ring-white outline-none"
                            >
                                {obCopy.skip}
                            </button>
                        </div>
                        {/* Body: accent 7.17:1 (UpgradePanel's accent/70 is 4.39:1 —
                            below AA for body text, so full accent here). */}
                        <p className="text-sm font-medium text-accent leading-relaxed mb-5">{obCopy.subheading}</p>

                        <div className="grid grid-cols-1 gap-3">
                            {/* Home card. Selectable-card look: translucent white on
                                the dark fill; selected = brighter fill + primary ring
                                + check badge (never colour alone). */}
                            <button
                                type="button"
                                onClick={function () { handleSelect('home'); }}
                                aria-pressed={homeSelected}
                                className={'relative w-full min-h-[44px] text-left p-4 rounded-xl flex items-center gap-3 btn-nature focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-forest outline-none ' +
                                    (homeSelected ? 'bg-white/[0.12] ring-2 ring-primary' : 'bg-white/[0.06] ring-1 ring-white/40 hover:ring-white/70')}
                            >
                                <div className={'w-11 h-11 shrink-0 rounded-2xl flex items-center justify-center ' +
                                    (homeSelected ? 'bg-primary' : 'bg-white/10')}>
                                    {obIcon('home', (homeSelected ? 'text-forest' : 'text-primary') + ' text-xl')}
                                </div>
                                <div className="min-w-0 flex-1 pr-7">
                                    <h3 className="font-extrabold text-sm text-white">
                                        {obCopy.homeTitle}
                                    </h3>
                                    <p className="text-xs font-semibold mt-0.5 text-accent">
                                        {obCopy.homeHint}
                                    </p>
                                </div>
                                {obSelMark(homeSelected)}
                            </button>

                            {/* Work card + inline occupation disclosure */}
                            <div className={'rounded-xl ' +
                                (workSelected ? 'bg-white/[0.12] ring-2 ring-primary' : 'bg-white/[0.06] ring-1 ring-white/40 hover:ring-white/70')}>
                                <button
                                    type="button"
                                    onClick={function () { handleSelect('work'); }}
                                    aria-pressed={workSelected}
                                    aria-expanded={workSelected}
                                    aria-controls="ob-role-group"
                                    className="relative w-full min-h-[44px] text-left p-4 rounded-xl flex items-center gap-3 btn-nature focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-forest outline-none"
                                >
                                    <div className={'w-11 h-11 shrink-0 rounded-2xl flex items-center justify-center ' +
                                        (workSelected ? 'bg-primary' : 'bg-white/10')}>
                                        {obIcon('engineering', (workSelected ? 'text-forest' : 'text-primary') + ' text-xl')}
                                    </div>
                                    <div className="min-w-0 flex-1 pr-7">
                                        <h3 className="font-extrabold text-sm text-white">
                                            {obCopy.workTitle}
                                        </h3>
                                        <p className="text-xs font-semibold mt-0.5 text-accent">
                                            {obCopy.workHint}
                                        </p>
                                    </div>
                                    {obSelMark(workSelected)}
                                </button>

                                {/* The disclosure sits on the dark panel, so its labels
                                    are primary / accent (legibility rule in reverse). */}
                                <div className={'ob-expand ' + (workSelected ? 'open' : '')} id="ob-role-group">
                                    <div><div className="px-4 pb-4">
                                        <p className="text-[10px] font-black uppercase tracking-widest text-primary mb-2">
                                            {obCopy.roleLabel}
                                        </p>
                                        <div className="flex flex-wrap gap-2" role="group" aria-label={obCopy.roleLabel}>
                                            {obRoleChips.map(function (c) {
                                                var pressed = chipId === c.id;
                                                // Unpressed: white on white/10 8.23:1, ring white/40
                                                // 3.16:1. Pressed: forest on primary 4.55:1 + check.
                                                return (
                                                    <button
                                                        key={c.id}
                                                        type="button"
                                                        onClick={function () { handleChip(c); }}
                                                        aria-pressed={pressed}
                                                        tabIndex={workSelected ? 0 : -1}
                                                        className={'ob-chip min-h-[44px] px-3.5 rounded-full text-xs font-bold inline-flex items-center gap-1 btn-nature focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-forest outline-none ' +
                                                            (pressed ? 'bg-primary text-forest' : 'bg-white/10 text-white ring-1 ring-white/40 hover:ring-white/70')}
                                                    >
                                                        {pressed && obIcon('check', 'text-sm -ml-0.5')}
                                                        {c.label}
                                                    </button>
                                                );
                                            })}
                                        </div>

                                        {/* "Something else" — a feedback capture (§10 decision 1):
                                            whatever the user types is persisted verbatim. */}
                                        <div className={'ob-expand ' + (otherNeedsText ? 'open' : '')}>
                                            <div><div className="pt-3">
                                                <label htmlFor="ob-role-other" className="block text-[10px] font-black uppercase tracking-widest text-primary mb-1.5">
                                                    {obCopy.roleOtherLabel}
                                                </label>
                                                {/* A white inset: forest text 11.09:1, placeholder
                                                    forest/70 4.61:1. */}
                                                <input
                                                    id="ob-role-other"
                                                    type="text"
                                                    maxLength={OB_ROLE_DETAIL_MAX}
                                                    autoComplete="organization-title"
                                                    value={roleOther}
                                                    onChange={function (e) { setRoleOther(e.target.value); }}
                                                    placeholder={obCopy.roleOtherPlaceholder}
                                                    tabIndex={otherNeedsText ? 0 : -1}
                                                    className="w-full min-h-[44px] rounded-xl border-0 bg-white text-forest text-sm font-bold px-3 py-2.5 placeholder:text-forest/70 placeholder:font-semibold focus:ring-2 focus:ring-primary outline-none"
                                                />
                                                <p className="text-xs font-medium text-accent mt-1.5">{obCopy.roleOtherHint}</p>
                                            </div></div>
                                        </div>
                                    </div></div>
                                </div>
                            </div>
                        </div>

                        {/* Primary pill: forest on primary 4.55:1 (white would be
                            2.44:1). Disabled: white/80 on white/10-over-forest
                            5.97:1 inside a white/40 outline (3.16:1) — still a
                            legible button, but plainly not the live primary. */}
                        <div className="mt-5">
                            <button
                                type="button"
                                onClick={handleStart}
                                disabled={!ctaEnabled}
                                className={'w-full min-h-[48px] font-extrabold rounded-full btn-nature py-3 text-sm flex items-center justify-center gap-2 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-offset-2 focus-visible:ring-offset-forest outline-none ' +
                                    (ctaEnabled ? 'bg-primary text-forest shadow-clay hover:brightness-110' : 'bg-white/10 text-white/80 ring-1 ring-white/40 cursor-not-allowed')}
                            >
                                {obCopy.cta}
                            </button>
                        </div>

                    </div>
                )}
                </div>
            </div>
        </div>
    );
};

window.OnboardingOverlay = OnboardingOverlay;
window.OnboardingResultCard = OnboardingResultCard;
window.obProfileLabel = obProfileLabel;
