/**
 * LocalCNNEnrichmentService — Enrichment-only wrapper for the Hybrid AI engine.
 *
 * Used exclusively by HybridStrategy in AIEngineAdapter. Runs LocalCNNService.analyze()
 * on the same image that Nyckel already processed, then returns only the enrichment
 * subset of the result — heatmap, frequency spectrum, saliency, and species.
 *
 * Why a separate service rather than calling LocalCNNService directly?
 *   1. Lifecycle isolation — Hybrid mode needs a load path that is independent
 *      of the full LOCAL_CNN engine path. App.jsx boot calls loadForEnrichment()
 *      only when AI_ENGINE='hybrid', keeping splash behaviour predictable.
 *   2. SPECIES_LIST flag gate at source — species fields are stripped here before
 *      the result reaches the adapter or any UI component. A single suppression
 *      point, not scattered across every rendering callsite.
 *   3. Enrichment shape contract — returns only the fields HybridStrategy needs,
 *      preventing accidental use of detection fields (percentage, verdict, severity)
 *      from the Local CNN pass, which would silently override the Nyckel verdict.
 *
 * Zero pipeline duplication — all inference runs inside LocalCNNService.analyze().
 * This service only shapes the result and manages load coordination.
 *
 * Public API:
 *   LocalCNNEnrichmentService.loadForEnrichment(onProgress) → Promise<void>
 *   LocalCNNEnrichmentService.isReady()                     → boolean
 *   LocalCNNEnrichmentService.enrich(imgElement, file, onStage) → Promise<EnrichmentFields>
 *
 * EnrichmentFields shape:
 *   {
 *     freqSpectrum         object|null
 *     saliencyLevel        string|null
 *     saliencyPeakToMean   number|null
 *     isShortcut           boolean
 *     heatmapDataURL       string|null
 *     speciesTop           object|null   — null when SPECIES_LIST disabled
 *     speciesRanked        array         — [] when SPECIES_LIST disabled
 *     speciesIsUncertain   boolean       — false when SPECIES_LIST disabled
 *     speciesSummary       string        — '' when SPECIES_LIST disabled
 *   }
 *
 * Depends on: LocalCNNService, FeatureFlags
 * ES5 — no const, let, arrow functions, template literals, optional chaining.
 */
var LocalCNNEnrichmentService = (function () {

    // ── State ─────────────────────────────────────────────────────────────────

    // Load state mirrors LocalCNNService load state — enrichment is ready when
    // the underlying models are ready. No separate model load is needed.
    var _loadInitiated = false;

    // ── Load lifecycle ────────────────────────────────────────────────────────

    /**
     * loadForEnrichment() — Triggers LocalCNNService model load for Hybrid mode.
     *
     * Called during App.jsx boot when AI_ENGINE='hybrid'.
     * Delegates to LocalCNNService.load() — models are shared, no duplication.
     * Idempotent: safe to call multiple times.
     *
     * @param {function} [onProgress] — optional stage label callback
     * @returns {Promise<void>}
     */
    function loadForEnrichment(onProgress) {
        if (_loadInitiated && LocalCNNService.getLoadState() === 'ready') {
            console.info('[LocalCNNEnrichment] Models already ready.');
            return Promise.resolve();
        }

        _loadInitiated = true;
        console.info('[LocalCNNEnrichment] Initiating model load for Hybrid enrichment...');

        return LocalCNNService.load(onProgress)
            .then(function () {
                console.info('[LocalCNNEnrichment] Models ready for enrichment.');
            })
            ['catch'](function (err) {
                _loadInitiated = false; // allow retry
                console.error('[LocalCNNEnrichment] Model load failed:', err.message);
                throw err;
            });
    }

    /**
     * isReady() — Returns true when LocalCNNService models are loaded and warmed up.
     * HybridStrategy checks this before calling enrich().
     */
    function isReady() {
        return LocalCNNService.getLoadState() === 'ready';
    }

    // ── Enrichment ────────────────────────────────────────────────────────────

    /**
     * enrich() — Run Local CNN pipeline and return only enrichment fields.
     *
     * Calls LocalCNNService.analyze() for the full pipeline result, then extracts
     * the enrichment subset. Detection fields (percentage, verdict, severity, insight)
     * are intentionally excluded — the Nyckel verdict is the source of truth in
     * Hybrid mode and must not be overridden by the Local CNN pass.
     *
     * SPECIES_LIST flag is evaluated here. When disabled, species fields are
     * set to null/empty regardless of what the model produced. This is the single
     * suppression point — no flag checks needed in UI components.
     *
     * @param {HTMLImageElement} imgElement — the same preview img element used for Nyckel
     * @param {File}             [file]     — raw File for frequency-consistent tensor path
     * @param {function}         [onStage]  — optional progress callback
     * @returns {Promise<EnrichmentFields>}
     */
    function enrich(imgElement, file, onStage) {
        if (!isReady()) {
            return Promise.reject(new Error('[LocalCNNEnrichment] Service not ready. Call loadForEnrichment() first.'));
        }

        var notify = onStage || function () {};

        return LocalCNNService.analyze(imgElement, notify, file)
            .then(function (fullResult) {
                return _extractEnrichmentFields(fullResult);
            });
    }

    /**
     * _extractEnrichmentFields() — Shape the enrichment subset from a full result.
     *
     * Strips detection fields. Applies SPECIES_LIST flag gate.
     * Called only from enrich() — not part of public API.
     *
     * @param {object} fullResult — complete LocalCNNService.analyze() result
     * @returns {EnrichmentFields}
     */
    function _extractEnrichmentFields(fullResult) {
        var speciesEnabled = FeatureFlags.isEnabled('SPECIES_LIST');

        return {
            freqSpectrum:        fullResult.freqSpectrum       || null,
            saliencyLevel:       fullResult.saliencyLevel      || null,
            saliencyPeakToMean:  fullResult.saliencyPeakToMean || null,
            isShortcut:          fullResult.isShortcut         || false,
            heatmapDataURL:      fullResult.heatmapDataURL     || null,
            // Species fields — suppressed at source when SPECIES_LIST is disabled
            speciesTop:          speciesEnabled ? (fullResult.speciesTop     || null) : null,
            speciesRanked:       speciesEnabled ? (fullResult.speciesRanked  || [])   : [],
            speciesIsUncertain:  speciesEnabled ? (fullResult.speciesIsUncertain || false) : false,
            speciesSummary:      speciesEnabled ? (fullResult.speciesSummary || '')   : ''
        };
    }

    // ── Public API ────────────────────────────────────────────────────────────

    return {
        loadForEnrichment: loadForEnrichment,
        isReady:           isReady,
        enrich:            enrich
    };

})();

window.LocalCNNEnrichmentService = LocalCNNEnrichmentService;
