/**
 * WaitlistService — client for the Mould Detect early-access waitlist API
 * (docs/waitlist-and-email.md, infra/waitlist/CLIENTS.md, in the website repo).
 *
 * Public API:
 *   WaitlistService.joinWaitlist(email) -> Promise<true>   (rejects on failure)
 *
 * ─────────────────────────────────────────────────────────────────────────────
 * WHY THIS CALLS THE API DIRECTLY (unlike AWSVisionService / CloudAssemblyVisionService)
 * ─────────────────────────────────────────────────────────────────────────────
 * Those two go through a same-origin proxy because their upstream calls carry a
 * secret API key that must never reach the browser. The waitlist endpoint has no
 * such secret — it is a public, honeypot-and-hash-protected POST meant to be
 * called straight from any client, browser included — so this module fetches
 * `https://api.moulddetect.ai/waitlist` directly. CORS for this app's origin
 * (mycology.moulddetect.ai + localhost) is the API's own responsibility.
 *
 * The `x-amz-content-sha256` header is required because CloudFront OAC signs
 * POSTs toward the Lambda Function URL and rejects an unsigned payload before it
 * ever reaches the application — same reason AWSVisionService sends it, same
 * recipe. It is duplicated here rather than imported from AWSVisionService on
 * purpose: this module has no other reason to depend on the vision stack's load
 * order, and the recipe is seven lines.
 *
 * ES5 — no const, let, arrow functions, template literals, spread, optional chaining.
 */
var WaitlistService = (function () {

    var config = window.MOULD_DETECT_CONFIG || {};

    var ENDPOINT   = config.waitlistEndpoint || 'https://api.moulddetect.ai/waitlist';
    var SOURCE     = 'react';
    var TIMEOUT_MS = 10000;

    // SHA-256 hex of the exact request body. Must be the hash of what is
    // actually sent — see the header comment. Web Crypto needs a secure
    // context (https / localhost), which describes every context where
    // CloudFront OAC is in front of us. If it is unavailable we send without
    // the header rather than a wrong one: a plain-http dev origin has no OAC
    // to satisfy, and a wrong hash would just be rejected anyway.
    function _sha256Hex(text) {
        var subtle = (typeof crypto !== 'undefined' && crypto && crypto.subtle) ? crypto.subtle : null;
        if (!subtle || typeof TextEncoder === 'undefined') return Promise.resolve(null);
        var bytes;
        try {
            bytes = new TextEncoder().encode(text);
        } catch (e) {
            return Promise.resolve(null);
        }
        return Promise.resolve(subtle.digest('SHA-256', bytes))
            .then(function (buffer) {
                var view = new Uint8Array(buffer);
                var hex = '';
                for (var i = 0; i < view.length; i++) {
                    var h = view[i].toString(16);
                    hex += (h.length === 1) ? ('0' + h) : h;
                }
                return hex;
            })
            ['catch'](function () { return null; });
    }

    /**
     * joinWaitlist — submit an email to the early-access waitlist.
     *
     * @param {string} email
     * @returns {Promise<true>} resolves true on 202/200; rejects with an Error
     *   on any other status, a network failure, or a timeout.
     */
    function joinWaitlist(email) {
        // Field order is part of the hashed bytes, so it is fixed here rather
        // than left to object-key iteration order. `website` is the honeypot:
        // a real client must always send it empty.
        var bodyText = JSON.stringify({ email: email, source: SOURCE, website: '' });

        return _sha256Hex(bodyText).then(function (hash) {
            var controller = (typeof AbortController !== 'undefined') ? new AbortController() : null;
            var timer = setTimeout(function () {
                if (controller) controller.abort();
            }, TIMEOUT_MS);

            var headers = { 'Content-Type': 'application/json' };
            if (hash) {
                headers['x-amz-content-sha256'] = hash;
            } else {
                console.warn('[WaitlistService] Web Crypto unavailable — sending without x-amz-content-sha256. This will be rejected by CloudFront OAC; expected only on a plain-http dev origin.');
            }

            var options = { method: 'POST', headers: headers, body: bodyText };
            if (controller) options.signal = controller.signal;

            return fetch(ENDPOINT, options).then(function (res) {
                clearTimeout(timer);
                if (res.status === 202 || res.status === 200) return true;
                throw new Error('waitlist signup failed (HTTP ' + res.status + ')');
            }, function (err) {
                clearTimeout(timer);
                throw err;
            });
        });
    }

    return {
        joinWaitlist: joinWaitlist,
        // Exposed for CloudAssemblyVisionService-style reuse and for tests;
        // not part of the documented contract.
        sha256Hex: _sha256Hex,
    };
})();

window.WaitlistService = WaitlistService;
