// ide-extension-data.test.mjs — Unit tests for knowledge-file loaders.
//
// Verifies loadTopJetBrains, loadJetBrainsBlocklist behavior + cache
// discipline shared with VS Code loaders.

import { describe, it, beforeEach } from 'node:test';
import assert from 'node:assert/strict';
import {
  loadTopJetBrains,
  loadJetBrainsBlocklist,
  loadTopVSCode,
  loadVSCodeBlocklist,
  normalizeId,
  _resetCache,
} from '../../scanners/lib/ide-extension-data.mjs';

describe('loadTopJetBrains', () => {
  beforeEach(() => _resetCache());

  it('returns >= 40 canonical xmlIds', async () => {
    const ids = await loadTopJetBrains();
    assert.ok(Array.isArray(ids));
    assert.ok(
      ids.length >= 40,
      `expected >= 40 entries, got ${ids.length}`,
    );
  });

  it('returns lowercased trimmed entries (normalizeId applied)', async () => {
    const ids = await loadTopJetBrains();
    for (const id of ids) {
      assert.equal(id, id.toLowerCase(), `not lowercased: ${id}`);
      assert.equal(id, id.trim(), `not trimmed: ${id}`);
      assert.notEqual(id, '', 'empty entry found');
    }
  });

  it('includes bundled JetBrains xmlIds', async () => {
    const ids = await loadTopJetBrains();
    assert.ok(
      ids.includes('com.intellij.java'),
      'missing com.intellij.java',
    );
    assert.ok(
      ids.includes('org.jetbrains.kotlin'),
      'missing org.jetbrains.kotlin',
    );
  });

  it('includes the legitimate-typo "lombook plugin" xmlId', async () => {
    const ids = await loadTopJetBrains();
    assert.ok(
      ids.includes('lombook plugin'),
      'missing "lombook plugin" — canonical xmlId for Lombok integration',
    );
  });
});

describe('loadJetBrainsBlocklist', () => {
  beforeEach(() => _resetCache());

  it('returns an empty array (empty by design)', async () => {
    const bl = await loadJetBrainsBlocklist();
    assert.ok(Array.isArray(bl));
    assert.equal(
      bl.length,
      0,
      'blocklist should be empty by design in v6.6.0',
    );
  });

  it('does not throw on repeated invocation', async () => {
    await assert.doesNotReject(() => loadJetBrainsBlocklist());
    await assert.doesNotReject(() => loadJetBrainsBlocklist());
  });
});

describe('cache sanity', () => {
  beforeEach(() => _resetCache());

  it('calling loadTopJetBrains then loadJetBrainsBlocklist does not throw', async () => {
    const ids = await loadTopJetBrains();
    const bl = await loadJetBrainsBlocklist();
    assert.ok(Array.isArray(ids) && ids.length > 0);
    assert.ok(Array.isArray(bl));
  });

  it('second loadTopJetBrains call returns same data (cache hit)', async () => {
    const a = await loadTopJetBrains();
    const b = await loadTopJetBrains();
    assert.deepEqual(a, b);
  });

  it('VS Code loaders still work alongside JetBrains loaders', async () => {
    const jb = await loadTopJetBrains();
    const vs = await loadTopVSCode();
    assert.ok(jb.length >= 40);
    assert.ok(Array.isArray(vs));
  });
});
