/**
 * StorageService — Persistence layer abstraction over localforage.
 *
 * Encapsulates all IndexedDB read/write operations.
 * If the storage backend changes, only this file needs updating.
 *
 * Storage keys:
 *   mould-detect-scans          — Array of scan records
 *   mould-detect-properties     — Array of property records
 *   mould-detect-heatmap:<id>   — Per-scan heatmap base64 (CR-02, stored
 *                                 outside the scans array so list reads and
 *                                 writes never touch heatmap payloads)
 *
 * Written in ES5 for Babel 6 compatibility.
 */
var StorageService = (function () {

    var SCANS_KEY = 'mould-detect-scans';
    var PROPERTIES_KEY = 'mould-detect-properties';
    var HEATMAP_KEY_PREFIX = 'mould-detect-heatmap:';

    // Configure localforage instance
    var store = localforage.createInstance({
        name: 'MouldDetect',
        storeName: 'app_data',
        description: 'MouldGuard AI application data',
    });

    /**
     * Strip large transient fields before persisting scans to conserve storage.
     * previewURL is a large base64 string only needed during the analysis flow.
     * heatmapDataURL lives under its own per-scan key (saveHeatmap), never in
     * the scans array — so every list read/write stays small (CR-02).
     * thumbnail (~5-15KB) is kept for card UI.
     */
    function prepareScanForStorage(scan) {
        var copy = {};
        for (var k in scan) {
            if (k === 'previewURL' || k === 'heatmapDataURL') continue;
            copy[k] = scan[k];
        }
        return copy;
    }

    // --- Heatmaps (per-scan keys, CR-02) ---

    function saveHeatmap(scanId, dataURL) {
        if (!scanId || !dataURL) return Promise.resolve();
        return store.setItem(HEATMAP_KEY_PREFIX + scanId, dataURL);
    }

    function loadHeatmap(scanId) {
        return store.getItem(HEATMAP_KEY_PREFIX + scanId);
    }

    function removeHeatmap(scanId) {
        return store.removeItem(HEATMAP_KEY_PREFIX + scanId);
    }

    // --- Scans ---

    function loadScans() {
        return store.getItem(SCANS_KEY).then(function (data) {
            return Array.isArray(data) ? data : [];
        });
    }

    // --- Properties ---

    function loadProperties() {
        return store.getItem(PROPERTIES_KEY).then(function (data) {
            return Array.isArray(data) ? data : [];
        });
    }

    // --- Batched persistence (serialised writes) ---

    var _writeQueue = Promise.resolve();

    /**
     * Persist both scans and properties. NOT atomic — two sequential setItem
     * calls; a failure between them can leave properties newer than scans
     * (readers tolerate this: unknown propertyIds render as "Unknown").
     * Writes are serialised via a queue — if a previous write is in-flight,
     * the new write waits for it to complete before starting.
     * CR-15: Retries once after 500ms on failure before logging.
     */
    function persistAll(scans, properties) {
        var doWrite = function () {
            var cleanedScans = [];
            for (var i = 0; i < scans.length; i++) {
                cleanedScans.push(prepareScanForStorage(scans[i]));
            }
            return store.setItem(PROPERTIES_KEY, properties).then(function () {
                return store.setItem(SCANS_KEY, cleanedScans);
            });
        };

        _writeQueue = _writeQueue.then(function () {
            return doWrite()['catch'](function (err) {
                console.warn('StorageService.persistAll: first attempt failed, retrying in 500ms...', err);
                return new Promise(function (resolve) { setTimeout(resolve, 500); }).then(doWrite);
            });
        })['catch'](function (err) {
            console.error('StorageService.persistAll failed after retry:', err);
        });
        return _writeQueue;
    }

    // --- Utility ---

    /**
     * getScanById — Load a single full scan record from IndexedDB by id.
     * Used by ScanDetails for on-demand heatmapDataURL loading (CR-02).
     * Returns the full persisted record including heatmapDataURL, or null.
     */
    function getScanById(id) {
        return store.getItem(SCANS_KEY).then(function (data) {
            var scans = Array.isArray(data) ? data : [];
            for (var i = 0; i < scans.length; i++) {
                if (scans[i].id === id) {
                    var scan = scans[i];
                    return loadHeatmap(id).then(function (heatmap) {
                        var copy = {};
                        for (var k in scan) { copy[k] = scan[k]; }
                        // Fall back to the inline field for records persisted
                        // before heatmaps moved to per-scan keys.
                        copy.heatmapDataURL = heatmap || scan.heatmapDataURL || null;
                        return copy;
                    });
                }
            }
            return null;
        });
    }

    return {
        loadScans: loadScans,
        loadProperties: loadProperties,
        persistAll: persistAll,
        saveHeatmap: saveHeatmap,
        loadHeatmap: loadHeatmap,
        removeHeatmap: removeHeatmap,
        getScanById: getScanById,
    };
})();

window.StorageService = StorageService;
