/**
 * Tiers — single source of truth for the five subscription tiers.
 *
 * Spec: architecture/ONBOARDING-PROFILE-MIGRATION-PLAN.md §6. Mirrors the website's
 * `site/js/components/PricingSections.js` (updated 2026-09-18) and the 2026-08-21
 * tier-naming decision. FIVE tiers — the onboarding prototype only had four
 * (it omitted Essential, which is the homeowner step-up named on the result card).
 *
 * Prices here are DISPLAY STRINGS and this file is the only place they live in the
 * React app. If the website's pricing changes, this file changes — one edit, and
 * every surface (onboarding result card, UpgradePanel, future entitlement seam)
 * follows. Nothing here enforces anything: `tierActive` on the user profile is what
 * a user HAS, `recommendedTier` is what onboarding SUGGESTS, and enforcement does
 * not exist yet (§7 — feature flags still stand in).
 *
 * Globals exported: `Tiers` (the table + helpers) and `obRecommendTier` (the
 * cohort/role → tier mapping the onboarding overlay calls). Everything else is
 * closed over inside the IIFE — the app has no module system, so every top-level
 * `var` would otherwise become a `window` global (CLAUDE.md hard rule).
 *
 * Written in ES5 for Babel 6 compatibility.
 */
var Tiers = (function () {

    // Ordered lowest → highest. Used for rank comparisons and for rendering a
    // pricing table in a stable order without relying on object key order.
    var TIER_IDS = ['free', 'essential', 'business', 'professional', 'enterprise'];

    var TIER_RANK = {
        free: 0,
        essential: 1,
        business: 2,
        professional: 3,
        enterprise: 4
    };

    /**
     * The capability matrix (§6). Booleans are capabilities; the string fields are
     * display copy. `pillClass` is the badge style used by the onboarding result
     * card — it honours the legibility rule (white text only on solid dark fills;
     * the Free pill is sage-on-white, never sage on a green fill).
     */
    var TIERS = {
        free: {
            id: 'free',
            label: 'Free',
            priceAud: 0,
            priceDisplay: 'A$0',
            priceLine: 'A$0',
            scanCap: '10 scans/mo',
            properties: '1 property',
            propertyCap: 1,
            reportType: 'Basic risk score',
            envData: 'Weather + environment data (capped)',
            reports: false,
            savedHistory: false,
            whiteLabelPdf: false,
            csvExport: false,
            missMould: false,
            team: false,
            api: false,
            // Forest label: sage on white was 2.65:1 (fails AA).
            pillClass: 'bg-white border border-sage text-forest'
        },
        essential: {
            id: 'essential',
            label: 'Essential',
            priceAud: 19.49,
            priceDisplay: 'A$19.49',
            priceLine: 'A$19.49/mo',
            scanCap: '100 scans/mo',
            properties: '2 properties',
            propertyCap: 2,
            reportType: 'Saved history + reports',
            envData: 'Weather + environment data (capped)',
            reports: true,
            savedHistory: true,
            whiteLabelPdf: false,
            csvExport: false,
            missMould: false,
            team: false,
            api: false,
            pillClass: 'bg-accent text-forest'
        },
        business: {
            id: 'business',
            label: 'Business',
            priceAud: 49,
            priceDisplay: 'A$49',
            priceLine: 'A$49/mo',
            scanCap: '300 scans/mo',
            properties: '10 properties',
            propertyCap: 10,
            reportType: 'White-label PDF reports',
            envData: 'Environment data (limited)',
            reports: true,
            savedHistory: true,
            whiteLabelPdf: true,
            csvExport: false,
            missMould: 'limited',
            team: false,
            api: false,
            pillClass: 'bg-terracotta text-white'
        },
        professional: {
            id: 'professional',
            label: 'Professional',
            priceAud: 199,
            priceDisplay: 'A$199',
            priceLine: 'A$199/mo',
            scanCap: '1,000 scans/mo',
            properties: '20 properties',
            propertyCap: 20,
            reportType: 'White-label PDF + CSV export',
            envData: 'Environment data included',
            reports: true,
            savedHistory: true,
            whiteLabelPdf: true,
            csvExport: true,
            missMould: true,
            team: true,
            api: false,
            pillClass: 'bg-forest text-white'
        },
        enterprise: {
            id: 'enterprise',
            label: 'Enterprise',
            priceAud: 399,
            priceDisplay: 'from A$399',
            priceLine: 'from A$399/mo',
            scanCap: 'Unlimited scans',
            properties: 'Unlimited properties',
            propertyCap: null,
            reportType: 'White-label PDF + CSV + insurer-ready data',
            envData: 'Environment data via API',
            reports: true,
            savedHistory: true,
            whiteLabelPdf: true,
            csvExport: true,
            missMould: true,
            team: true,
            api: true,
            pillClass: 'bg-primary text-white'
        }
    };

    // Cohort → tier, for the paths that carry no occupation (§6).
    var COHORT_TIER = {
        homeowner: 'free',
        business: 'business',
        professional: 'professional',
        enterprise: 'enterprise',
        unsure: 'free'
    };

    // Occupation → tier (§6 + §10 decision 1: "other" recommends business, the
    // lowest paid pro tier, and the free-text roleDetail is kept as the signal).
    var ROLE_TIER = {
        cleaner: 'business',
        plumber: 'business',
        inspector: 'professional',
        remediator: 'professional',
        franchise: 'professional',
        hygienist: 'enterprise',
        lab: 'enterprise',
        university: 'enterprise',
        other: 'business'
    };

    // Cohort labels for display (the onboarding result card's eyebrow line).
    var COHORT_LABELS = {
        homeowner: 'Homeowner / Renter',
        business: 'Business',
        professional: 'Professional',
        enterprise: 'Enterprise',
        unsure: 'Not sure yet'
    };

    /** get — the tier record for an id; falls back to Free for anything unknown. */
    function get(id) {
        return TIERS[id] || TIERS.free;
    }

    /** rank — numeric rank (free 0 … enterprise 4); unknown ids rank as free. */
    function rank(id) {
        return (TIER_RANK[id] != null) ? TIER_RANK[id] : 0;
    }

    /** higher — the higher-ranked of two tier ids. */
    function higher(a, b) {
        return rank(a) >= rank(b) ? (TIERS[a] ? a : 'free') : (TIERS[b] ? b : 'free');
    }

    /** isAtLeast — rank comparison, the shape a future entitlement check will want. */
    function isAtLeast(id, minimum) {
        return rank(id) >= rank(minimum);
    }

    /** label / price — convenience string readers for UI copy. */
    function label(id) {
        return get(id).label;
    }

    function price(id) {
        return get(id).priceLine;
    }

    /** cohortLabel — display label for an onboarding cohort value. */
    function cohortLabel(cohort) {
        return COHORT_LABELS[cohort] || COHORT_LABELS.unsure;
    }

    /**
     * unlocks — the three "what you get" lines the onboarding result card shows.
     * Kept here so the card never composes plan claims of its own.
     */
    function unlocks(id) {
        var t = get(id);
        return [t.scanCap, t.reportType, t.envData];
    }

    /** all — the five tier records in rank order (for a pricing table). */
    function all() {
        var out = [];
        for (var i = 0; i < TIER_IDS.length; i++) out.push(TIERS[TIER_IDS[i]]);
        return out;
    }

    /**
     * recommend(cohort, role) — the onboarding recommendation mapping (§6).
     *
     * Occupation wins when we have one (it is the finer signal); otherwise the
     * cohort decides. Homeowners and "just exploring" get Free — the result card
     * names Essential as the step-up rather than recommending a paid tier for a
     * cohort that did not ask for one (§10 decision 2).
     *
     * Never throws and never returns undefined: an unknown cohort or role is Free.
     */
    function recommend(cohort, role) {
        if (role && ROLE_TIER[role]) return ROLE_TIER[role];
        if (cohort && COHORT_TIER[cohort]) return COHORT_TIER[cohort];
        return 'free';
    }

    /**
     * stepUpFor — the tier to name as the upsell for a recommended tier, or null.
     * Today only Free has one (Essential), which is how Essential enters the flow
     * without adding a question.
     */
    function stepUpFor(recommendedTier) {
        return recommendedTier === 'free' ? 'essential' : null;
    }

    /** nextUp — the next paid tier above `id` in rank order, or null at the top.
     *  Used for SUBSCRIBED users (canonical tier): never upsell sideways or down. */
    function nextUp(id) {
        var i = TIER_IDS.indexOf(id);
        if (i < 0) return 'essential';
        return TIER_IDS[i + 1] || null;
    }

    return {
        IDS: TIER_IDS,
        RANK: TIER_RANK,
        TIERS: TIERS,
        COHORT_TIER: COHORT_TIER,
        ROLE_TIER: ROLE_TIER,
        COHORT_LABELS: COHORT_LABELS,
        get: get,
        all: all,
        rank: rank,
        nextUp: nextUp,
        higher: higher,
        isAtLeast: isAtLeast,
        label: label,
        price: price,
        cohortLabel: cohortLabel,
        unlocks: unlocks,
        recommend: recommend,
        stepUpFor: stepUpFor
    };
})();

/**
 * obRecommendTier — the name the migration plan (§6) gives the recommendation
 * mapping, exported as a plain function for the onboarding overlay. Same
 * implementation as Tiers.recommend; `ob` is the onboarding namespace prefix.
 */
var obRecommendTier = function (cohort, role) {
    return Tiers.recommend(cohort, role);
};

window.Tiers = Tiers;
window.obRecommendTier = obRecommendTier;
