import { findAllSequences, tokensEqual, formatAnchor } from './tokens';
import type { Token } from './types';

// A helper to create mock tokens for testing
const makeTokens = (texts: string[]): Token[] => {
  let startIndex = 0;
  return texts.map((text) => {
    const token: Token = {
      text,
      type: 'identifier', // type and positions are not important for these tests
      startIndex: startIndex,
      endIndex: startIndex + text.length,
      startPosition: { row: 0, column: startIndex },
    };
    startIndex += text.length + 1; // +1 for space
    return token;
  });
};

describe('token-utils', () => {
  describe('findAllSequences', () => {
    it('should find a single unique sequence', () => {
      const haystack = makeTokens(['a', 'b', 'c', 'd', 'e']);
      const needle = makeTokens(['b', 'c']);
      const indices = findAllSequences(haystack, needle);
      expect(indices).toEqual([1]);
    });

    it('should find multiple occurrences of a sequence', () => {
      const haystack = makeTokens(['a', 'b', 'c', 'a', 'b', 'c']);
      const needle = makeTokens(['a', 'b', 'c']);
      const indices = findAllSequences(haystack, needle);
      expect(indices).toEqual([0, 3]);
    });

    it('should return an empty array if sequence is not found', () => {
      const haystack = makeTokens(['a', 'b', 'c']);
      const needle = makeTokens(['d', 'e']);
      const indices = findAllSequences(haystack, needle);
      expect(indices).toEqual([]);
    });

    it('should return an empty array for an empty needle', () => {
      const haystack = makeTokens(['a', 'b', 'c']);
      const needle = makeTokens([]);
      const indices = findAllSequences(haystack, needle);
      expect(indices).toEqual([]);
    });

    it('should handle sequences at the beginning and end of haystack', () => {
      const haystack = makeTokens(['a', 'b', 'c', 'd', 'a', 'b']);
      const needleAtStart = makeTokens(['a', 'b']);
      const needleAtEnd = makeTokens(['a', 'b']);
      expect(findAllSequences(haystack, needleAtStart)).toEqual([0, 4]);
      expect(findAllSequences(haystack, needleAtEnd)).toEqual([0, 4]);
    });
  });

  describe('tokensEqual', () => {
    it('should return true for tokens with same text', () => {
      const tokenA = makeTokens(['hello'])[0];
      const tokenB = makeTokens(['hello'])[0];
      expect(tokensEqual(tokenA, tokenB)).toBe(true);
    });

    it('should return false for tokens with different text', () => {
      const tokenA = makeTokens(['hello'])[0];
      const tokenB = makeTokens(['world'])[0];
      expect(tokensEqual(tokenA, tokenB)).toBe(false);
    });
  });

  describe('formatAnchor', () => {
    it('should format an anchor to a space-separated string', () => {
      const anchor = makeTokens(['const', 'x', '=', '1', ';']);
      expect(formatAnchor(anchor)).toBe('const x = 1 ;');
    });

    it('should return an empty string for an empty anchor', () => {
      const anchor = makeTokens([]);
      expect(formatAnchor(anchor)).toBe('');
    });
  });
});
