import { TextSelection } from './TextSelection';

describe('TextSelection', () => {
  let textarea: any; // Use 'any' type to mock the necessary properties and methods
  let textSelection: TextSelection;

  beforeEach(() => {
    textarea = {
      value: 'Hello, world!',
      selectionStart: 0,
      selectionEnd: 0,
      focus: jest.fn(),
      setRangeText: jest.fn((text: string) => {
        const start = textarea.selectionStart;
        const end = textarea.selectionEnd;
        textarea.value =
          textarea.value.substring(0, start) +
          text +
          textarea.value.substring(end);
        textarea.selectionStart = start + text.length;
        textarea.selectionEnd = start + text.length;
      }),
      dispatchEvent: jest.fn()
    };

    textSelection = new TextSelection(textarea);
  });

  test('constructor should initialize the properties correctly', () => {
    expect(textSelection.elm).toBe(textarea);
    expect(textSelection.start).toBe(textarea.selectionStart);
    expect(textSelection.end).toBe(textarea.selectionEnd);
    expect(textSelection.value).toBe(textarea.value);
  });

  test('position() should update the start and end properties', () => {
    const start = 2;
    const end = 5;
    textSelection.position(start, end);
    expect(textSelection.start).toBe(start);
    expect(textSelection.end).toBe(end);
  });

  test('insertText() should insert text at the current cursor position', () => {
    const text = 'Hello, world!';
    textarea.value = 'Lorem ipsum dolor sit amet';
    const originalValue = textarea.value;

    // Mock selectionStart and selectionEnd properties
    Object.defineProperty(textarea, 'selectionStart', { value: 6 });
    Object.defineProperty(textarea, 'selectionEnd', { value: 6 });

    textSelection.insertText(text);

    // Verify that the text is inserted at the correct position
    expect(textarea.value).toBe(
      originalValue.slice(0, 6) + text + originalValue.slice(6)
    );
    // Verify that start and end properties are updated correctly
    expect(textSelection.start).toBe(6 + text.length);
    expect(textSelection.end).toBe(6 + text.length);
  });

  test('notifyChange() should dispatch an input event', () => {
    const dispatchMock = jest.fn();
    textarea.dispatchEvent = dispatchMock;

    textSelection.notifyChange();

    expect(dispatchMock).toHaveBeenCalledTimes(1);
    expect(dispatchMock).toHaveBeenCalledWith(expect.any(Event));
  });

  describe('position()', () => {
    it('should set the selection start and end positions', () => {
      textSelection.position(2, 6);

      expect(textSelection.start).toEqual(2);
      expect(textSelection.end).toEqual(6);
      expect(textSelection.elm.selectionStart).toEqual(2);
      expect(textSelection.elm.selectionEnd).toEqual(6);
    });

    it('should default to the current selection positions if no arguments are passed', () => {
      textSelection.position();

      expect(textSelection.start).toEqual(textarea.selectionStart);
      expect(textSelection.end).toEqual(textarea.selectionEnd);
      expect(textSelection.elm.selectionStart).toEqual(textarea.selectionStart);
      expect(textSelection.elm.selectionEnd).toEqual(textarea.selectionEnd);
    });
  });

  describe('insertText()', () => {
    it('should insert text at the current cursor position', () => {
      textSelection.position(7, 7);
      textSelection.insertText('beautiful ');

      expect(textSelection.value).toEqual('Hello, beautiful world!');
      expect(textarea.value).toEqual('Hello, beautiful world!');
      expect(textarea.selectionStart).toEqual(17);
      expect(textarea.selectionEnd).toEqual(17);
    });
  });

  describe('getSelectedValue()', () => {
    it('should return the selected text', () => {
      console.log('textSelection', textSelection);
      textSelection.position(2, 6);
      const selectedValue = textSelection.getSelectedValue();

      expect(selectedValue).toEqual('llo,');
    });
  });
});
