import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { getTriggerInfo, filteredSkills } from '../utils/autocomplete.js';

const mockConfig = {
  trigger: '/',
  skills: [
    { name: 'commit', description: 'Create a git commit' },
    { name: 'review-pr', description: 'Review a pull request' },
    { name: 'comment', description: 'Add a comment' },
  ],
};

describe('getTriggerInfo', () => {
  it('returns null when no autocompleteConfig', () => {
    const result = getTriggerInfo('/hello', 1, null);
    assert.equal(result, null);
  });

  it('returns null when autocompleteConfig is undefined', () => {
    const result = getTriggerInfo('/hello', 1, undefined);
    assert.equal(result, null);
  });

  it('detects trigger at position 0', () => {
    const result = getTriggerInfo('/', 1, mockConfig);
    assert.deepEqual(result, {
      trigger: '/',
      filterText: '',
      replaceStart: 0,
      replaceEnd: 1,
    });
  });

  it('detects trigger after space', () => {
    const result = getTriggerInfo('hello /co', 9, mockConfig);
    assert.deepEqual(result, {
      trigger: '/',
      filterText: 'co',
      replaceStart: 6,
      replaceEnd: 9,
    });
  });

  it('detects trigger after newline', () => {
    const result = getTriggerInfo('line1\n/rev', 10, mockConfig);
    assert.deepEqual(result, {
      trigger: '/',
      filterText: 'rev',
      replaceStart: 6,
      replaceEnd: 10,
    });
  });

  it('returns null for non-trigger character', () => {
    const result = getTriggerInfo('hello world', 5, mockConfig);
    assert.equal(result, null);
  });

  it('returns null for wrong trigger (! when config expects /)', () => {
    const result = getTriggerInfo('!commit', 7, mockConfig);
    assert.equal(result, null);
  });

  it('returns null for trigger embedded in a word', () => {
    const result = getTriggerInfo('path/to/file', 5, mockConfig);
    assert.equal(result, null);
  });

  it('extracts filterText correctly', () => {
    const result = getTriggerInfo('/commit', 7, mockConfig);
    assert.equal(result.filterText, 'commit');
    assert.equal(result.replaceStart, 0);
    assert.equal(result.replaceEnd, 7);
  });

  it('filterText is lowercase', () => {
    const result = getTriggerInfo('/CoMmIt', 7, mockConfig);
    assert.equal(result.filterText, 'commit');
  });

  it('replaceStart and replaceEnd are correct for mid-input trigger', () => {
    const result = getTriggerInfo('foo /bar', 8, mockConfig);
    assert.equal(result.replaceStart, 4);
    assert.equal(result.replaceEnd, 8);
  });

  it('works with a different trigger character', () => {
    const codexConfig = { trigger: '!', skills: [] };
    const result = getTriggerInfo('!test', 5, codexConfig);
    assert.deepEqual(result, {
      trigger: '!',
      filterText: 'test',
      replaceStart: 0,
      replaceEnd: 5,
    });
  });
});

describe('filteredSkills', () => {
  it('returns empty array without config', () => {
    const info = { filterText: '' };
    assert.deepEqual(filteredSkills(null, info), []);
  });

  it('returns empty array without triggerInfo', () => {
    assert.deepEqual(filteredSkills(mockConfig, null), []);
  });

  it('returns empty array when both are null', () => {
    assert.deepEqual(filteredSkills(null, null), []);
  });

  it('returns all skills with empty filter', () => {
    const info = { filterText: '' };
    const result = filteredSkills(mockConfig, info);
    assert.equal(result.length, 3);
  });

  it('filters case-insensitively', () => {
    const info = { filterText: 'com' };
    const result = filteredSkills(mockConfig, info);
    const names = result.map(s => s.name);
    assert.ok(names.includes('commit'));
    assert.ok(names.includes('comment'));
    assert.ok(!names.includes('review-pr'));
  });

  it('matches anywhere in name', () => {
    const info = { filterText: 'view' };
    const result = filteredSkills(mockConfig, info);
    assert.equal(result.length, 1);
    assert.equal(result[0].name, 'review-pr');
  });

  it('sorts alphabetically', () => {
    const info = { filterText: '' };
    const result = filteredSkills(mockConfig, info);
    const names = result.map(s => s.name);
    assert.deepEqual(names, ['comment', 'commit', 'review-pr']);
  });

  it('returns empty array when no matches', () => {
    const info = { filterText: 'zzz' };
    const result = filteredSkills(mockConfig, info);
    assert.deepEqual(result, []);
  });

  it('does not mutate the original skills array', () => {
    const config = {
      trigger: '/',
      skills: [
        { name: 'zebra', description: 'z' },
        { name: 'alpha', description: 'a' },
      ],
    };
    const info = { filterText: '' };
    filteredSkills(config, info);
    assert.equal(config.skills[0].name, 'zebra');
    assert.equal(config.skills[1].name, 'alpha');
  });
});
