'use strict';

const fs = require('fs');
const path = require('path');

/**
 * FileBackend — reads JSON payloads from a directory on disk.
 *
 * Two layouts supported:
 *   - 'per-id'      one file per id (filename minus .json is the id)
 *   - 'single-file' one file containing an array; index by a field name
 *
 * Returns Map<lowerCaseId, payload>. Case-insensitive lookups by default —
 * matches how loadCurve worked historically.
 */
class FileBackend {
    constructor(opts = {}) {
        const {
            baseDir,
            layout = 'per-id',
            filePath,
            arrayKey,
            indexField,
            exclude = [],
            caseInsensitive = true,
        } = opts;

        if (!baseDir) throw new TypeError('FileBackend: baseDir is required');
        if (layout !== 'per-id' && layout !== 'single-file') {
            throw new TypeError(`FileBackend: unsupported layout '${layout}'`);
        }
        if (layout === 'single-file' && !filePath) {
            throw new TypeError('FileBackend: single-file layout requires filePath');
        }

        this.baseDir = baseDir;
        this.layout = layout;
        this.filePath = filePath;
        this.arrayKey = arrayKey;
        this.indexField = indexField;
        this.exclude = new Set(exclude);
        this.caseInsensitive = caseInsensitive;
    }

    _norm(k) {
        return this.caseInsensitive ? String(k).toLowerCase() : String(k);
    }

    loadAll() {
        if (this.layout === 'per-id') return this._loadPerId();
        return this._loadSingleFile();
    }

    async refresh() {
        // No actual I/O penalty on local disk; the async surface exists so
        // callers can `await resolver.refresh()` symmetrically with future
        // HttpBackend implementations.
        return this.loadAll();
    }

    _loadPerId() {
        const map = new Map();
        if (!fs.existsSync(this.baseDir)) return map;
        const entries = fs.readdirSync(this.baseDir, { withFileTypes: true });
        for (const entry of entries) {
            if (!entry.isFile()) continue;
            if (!entry.name.endsWith('.json')) continue;
            const id = path.basename(entry.name, '.json');
            if (this.exclude.has(id)) continue;
            const raw = fs.readFileSync(path.join(this.baseDir, entry.name), 'utf8');
            const data = JSON.parse(raw);
            map.set(this._norm(id), data);
        }
        return map;
    }

    _loadSingleFile() {
        const full = path.resolve(this.baseDir, this.filePath);
        if (!fs.existsSync(full)) return new Map();
        const data = JSON.parse(fs.readFileSync(full, 'utf8'));
        const arr = this.arrayKey ? data[this.arrayKey] : data;
        if (!Array.isArray(arr)) {
            throw new Error(
                `FileBackend(single-file): expected array at ${this.arrayKey || '<root>'} in ${full}`,
            );
        }
        const map = new Map();
        for (const entry of arr) {
            const k = entry && this.indexField ? entry[this.indexField] : null;
            if (k != null) map.set(this._norm(k), entry);
        }
        return map;
    }
}

module.exports = FileBackend;
