'use strict';

const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const os = require('os');
const path = require('path');

const FileBackend = require('../../src/registry/backends/FileBackend');

function tmpdir(prefix) {
    return fs.mkdtempSync(path.join(os.tmpdir(), `evolv-fb-${prefix}-`));
}

test('per-id layout: one file per id, lowercased keys', () => {
    const dir = tmpdir('perid');
    fs.writeFileSync(path.join(dir, 'AlphaModel.json'), JSON.stringify({ kind: 'pump' }));
    fs.writeFileSync(path.join(dir, 'beta.json'),       JSON.stringify({ kind: 'valve' }));
    const b = new FileBackend({ baseDir: dir, layout: 'per-id' });
    const m = b.loadAll();
    assert.equal(m.get('alphamodel').kind, 'pump');
    assert.equal(m.get('beta').kind,       'valve');
});

test('per-id: case-sensitive mode preserves key casing', () => {
    const dir = tmpdir('case');
    fs.writeFileSync(path.join(dir, 'Mixed.json'), JSON.stringify({ ok: true }));
    const b = new FileBackend({ baseDir: dir, layout: 'per-id', caseInsensitive: false });
    const m = b.loadAll();
    assert.ok(m.has('Mixed'));
    assert.ok(!m.has('mixed'));
});

test('per-id: exclude list skips named files', () => {
    const dir = tmpdir('excl');
    fs.writeFileSync(path.join(dir, 'good.json'), '{}');
    fs.writeFileSync(path.join(dir, 'bad.json'),  '{}');
    const b = new FileBackend({ baseDir: dir, layout: 'per-id', exclude: ['bad'] });
    const m = b.loadAll();
    assert.ok(m.has('good'));
    assert.ok(!m.has('bad'));
});

test('per-id: missing baseDir → empty map', () => {
    const b = new FileBackend({ baseDir: '/no/such/dir', layout: 'per-id' });
    assert.equal(b.loadAll().size, 0);
});

test('single-file: indexes array by named field', () => {
    const dir = tmpdir('single');
    const file = 'data.json';
    fs.writeFileSync(path.join(dir, file), JSON.stringify({
        samples: [
            { code: '001', desc: 'one' },
            { code: '002', desc: 'two' },
        ],
    }));
    const b = new FileBackend({
        baseDir: dir, layout: 'single-file', filePath: file,
        arrayKey: 'samples', indexField: 'code',
    });
    const m = b.loadAll();
    assert.equal(m.get('001').desc, 'one');
    assert.equal(m.get('002').desc, 'two');
});

test('single-file: missing file → empty map', () => {
    const dir = tmpdir('miss');
    const b = new FileBackend({
        baseDir: dir, layout: 'single-file', filePath: 'nope.json',
        arrayKey: 'samples', indexField: 'code',
    });
    assert.equal(b.loadAll().size, 0);
});

test('single-file: bad shape throws', () => {
    const dir = tmpdir('bad');
    fs.writeFileSync(path.join(dir, 'data.json'), JSON.stringify({ samples: 'not-array' }));
    const b = new FileBackend({
        baseDir: dir, layout: 'single-file', filePath: 'data.json',
        arrayKey: 'samples', indexField: 'code',
    });
    assert.throws(() => b.loadAll(), /expected array/i);
});

test('refresh() returns same result as loadAll() for file backend', async () => {
    const dir = tmpdir('refresh');
    fs.writeFileSync(path.join(dir, 'a.json'), JSON.stringify({ v: 1 }));
    const b = new FileBackend({ baseDir: dir, layout: 'per-id' });
    const r = await b.refresh();
    assert.equal(r.get('a').v, 1);
});

test('constructor validates layout + filePath combinations', () => {
    assert.throws(() => new FileBackend({}),                                        /baseDir/);
    assert.throws(() => new FileBackend({ baseDir: '/tmp', layout: 'weird' }),      /layout/);
    assert.throws(() => new FileBackend({ baseDir: '/tmp', layout: 'single-file' }), /filePath/);
});
