// @flow
import {
  getTokenIndexes,
  isTokenValid,
  splitStringByFirstToken,
  splitStyledTextByToken,
} from './inline-styled-text.helpers';

describe('InlineStyledText Utility', () => {
  describe('HELPER: getTokenIndexes', () => {
    const token = { start: '[[', end: ']]' };

    it('MISSING TOKEN: it should return a -1 when the start or end cannot be found', () => {
      const noStart = 'text]]';
      const noEnd = '[[text';

      expect(getTokenIndexes(noStart, token).start).toEqual(-1);
      expect(getTokenIndexes(noEnd, token).end).toEqual(-1);
    });

    it('VALID INPUT: it should return the index of where the token start and end are located in the string', () => {
      const text = '[[text]]';
      const expected = { start: 0, end: 6 };

      expect(getTokenIndexes(text, token)).toEqual(expected);
    });
  });

  describe('HELPER: isTokenValid', () => {
    it('INVALID TOKEN: it should return false when start or end is missing or when end appears before start', () => {
      const noStart = { start: -1, end: 6 };
      const noEnd = { start: 0, end: -1 };
      const startAfterEnd = { start: 10, end: 5 };

      expect(isTokenValid(noStart)).toEqual(false);
      expect(isTokenValid(noEnd)).toEqual(false);
      expect(isTokenValid(startAfterEnd)).toEqual(false);
    });

    it('VALID TOKEN: it should return true when start and end are not -1 and start is less than end', () => {
      const tokenIndexes = { start: 1, end: 10 };

      expect(isTokenValid(tokenIndexes)).toEqual(true);
    });
  });

  describe('HELPER: splitStringByFirstToken', () => {
    const token = { start: '[[', end: ']]' };

    it('VALID TEXT: return an object containing the prefix, styled, and suffix', () => {
      const segments = ["Hello it's ", 'me', ', I was wondering'];
      const text = "Hello it's [[me]], I was wondering";
      const tokenIndexes = { start: 11, end: 15 };
      const expected = {
        prefix: segments[0],
        styled: segments[1],
        suffix: segments[2],
      };

      expect(splitStringByFirstToken(text, token, tokenIndexes)).toEqual(
        expected,
      );
    });

    it('NO PREFIX: return an object containing an empty prefix, populated styled, and populated suffix', () => {
      const segments = ['', 'me', ', I was wondering'];
      const text = '[[me]], I was wondering';
      const tokenIndexes = { start: 0, end: 4 };
      const expected = {
        prefix: segments[0],
        styled: segments[1],
        suffix: segments[2],
      };

      expect(splitStringByFirstToken(text, token, tokenIndexes)).toEqual(
        expected,
      );
    });

    it('NO SUFFIX: return an object containing a populated prefix, populated styled, and an empty suffix', () => {
      const segments = ["Hello it's ", 'me', ''];
      const text = "Hello it's [[me]]";
      const tokenIndexes = { start: 11, end: 15 };
      const expected = {
        prefix: segments[0],
        styled: segments[1],
        suffix: segments[2],
      };

      expect(splitStringByFirstToken(text, token, tokenIndexes)).toEqual(
        expected,
      );
    });
  });

  describe('UTILITY: splitStyledTextByToken', () => {
    it('EMPTY STRING: Should return an empty array when given an empty string', () => {
      const text = '';
      const expected = [];

      expect(splitStyledTextByToken(text)).toEqual(expected);
    });

    it('NO TOKEN: Should return an array with one unstyled segment', () => {
      const text = 'text';
      const expected = [{ applyInlineStyle: false, text }];

      expect(splitStyledTextByToken(text)).toEqual(expected);
    });

    it('INVALID TOKEN: Should return an array with one unstyled segment', () => {
      const text = 'text ]]styled[[';
      const expected = [{ applyInlineStyle: false, text }];

      expect(splitStyledTextByToken(text)).toEqual(expected);
    });

    it('INCOMPLETE TOKEN: Should return an array with one unstyled segment', () => {
      const textOne = 'text ]]styled';
      const expectedOne = [{ applyInlineStyle: false, text: textOne }];
      expect(splitStyledTextByToken(textOne)).toEqual(expectedOne);

      const textTwo = 'text[[styled';
      const expectedTwo = [{ applyInlineStyle: false, text: textTwo }];
      expect(splitStyledTextByToken(textTwo)).toEqual(expectedTwo);
    });

    it("VALID TEXT: returns array of text segments with the tokenized segment's applyInlineStyle flag being set to true", () => {
      const segments = ["Hello it's ", 'me', ', I was wondering'];
      const text = "Hello it's [[me]], I was wondering";
      const expected = [
        { applyInlineStyle: false, text: segments[0] },
        { applyInlineStyle: true, text: segments[1] },
        { applyInlineStyle: false, text: segments[2] },
      ];

      expect(splitStyledTextByToken(text)).toEqual(expected);
    });

    it("CUSTOM TOKEN: returns array of text segments with the tokenized segment's applyInlineStyle flag being set to true", () => {
      const segments = ["Hello it's ", 'me', ', I was wondering'];
      const customToken = { start: '((', end: '))' };
      const text = "Hello it's ((me)), I was wondering";
      const expected = [
        { applyInlineStyle: false, text: segments[0] },
        { applyInlineStyle: true, text: segments[1] },
        { applyInlineStyle: false, text: segments[2] },
      ];

      expect(splitStyledTextByToken(text, customToken)).toEqual(expected);
    });

    it('NO PREFIX: returns an array with styled segment first when the tokenized text is at the start of the string', () => {
      const segments = ['WOAH', ', slow down!'];
      const text = '[[WOAH]], slow down!';
      const expected = [
        { applyInlineStyle: true, text: segments[0] },
        { applyInlineStyle: false, text: segments[1] },
      ];

      expect(splitStyledTextByToken(text)).toEqual(expected);
    });

    it('NO SUFFIX: returns an array with styled segment last when the tokenized text is at the end of the string', () => {
      const segments = ['WOAH, ', 'slow down!'];
      const text = 'WOAH, [[slow down!]]';
      const expected = [
        { applyInlineStyle: false, text: segments[0] },
        { applyInlineStyle: true, text: segments[1] },
      ];

      expect(splitStyledTextByToken(text)).toEqual(expected);
    });

    it('MULTIPLE TOKENS: returns an array with more than one styled segment when the string has multiple instances of the token', () => {
      const segments = [
        "Hello it's ",
        'me',
        ', I was wondering if you could ',
        'help',
        ' me out?',
      ];
      const text =
        "Hello it's [[me]], I was wondering if you could [[help]] me out?";
      const expected = [
        { applyInlineStyle: false, text: segments[0] },
        { applyInlineStyle: true, text: segments[1] },
        { applyInlineStyle: false, text: segments[2] },
        { applyInlineStyle: true, text: segments[3] },
        { applyInlineStyle: false, text: segments[4] },
      ];

      expect(splitStyledTextByToken(text)).toEqual(expected);
    });
  });
});
