import React from 'react';
import { mountWithIntl, shallowWithIntl } from '../../../../../helpers/intl-enzym-test-helpers';
import CapInput from '@capillarytech/cap-ui-library/CapInput';
import ButtonForm from '../ButtonForm';
import messages from '../../messages';

describe('ButtonForm', () => {
  const mockFormatMessage = jest.fn((message) => message.defaultMessage || message);
  const mockOnSave = jest.fn();
  const mockOnCancel = jest.fn();

  const defaultProps = {
    buttonType: 'primary',
    formatMessage: mockFormatMessage,
    onSave: mockOnSave,
    onCancel: mockOnCancel,
    initialData: null,
    isEditMode: false,
  };

  // Helper function to find CapInput by id
  const findCapInputById = (wrapper, id) => {
    return wrapper.find(CapInput).findWhere((node) => node.prop('id') === id).first();
  };

  // Helper function to find the actual input element inside CapInput
  const findInputElement = (wrapper, id) => {
    const capInput = findCapInputById(wrapper, id);
    // CapInput wraps an actual input element - find it
    return capInput.find('input').first();
  };

  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('Rendering', () => {
    it('should render correctly with default props', () => {
      const wrapper = shallowWithIntl(<ButtonForm {...defaultProps} />);
      expect(wrapper).toMatchSnapshot();
    });

    it('should render correctly for primary button type', () => {
      const wrapper = shallowWithIntl(<ButtonForm {...defaultProps} buttonType="primary" />);
      expect(wrapper).toMatchSnapshot();
    });

    it('should render correctly for secondary button type', () => {
      const wrapper = shallowWithIntl(<ButtonForm {...defaultProps} buttonType="secondary" />);
      expect(wrapper).toMatchSnapshot();
    });

    it('should render correctly with initial data', () => {
      const initialData = {
        text: 'Click me',
        url: 'https://example.com',
      };
      const wrapper = shallowWithIntl(
        <ButtonForm {...defaultProps} initialData={initialData} />
      );
      expect(wrapper).toMatchSnapshot();
    });

    it('should render correctly in edit mode', () => {
      const wrapper = shallowWithIntl(<ButtonForm {...defaultProps} isEditMode={true} />);
      expect(wrapper).toMatchSnapshot();
    });

    it('should render character count suffix', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const characterCount = wrapper.find('.button-character-count-suffix');
      expect(characterCount.exists()).toBe(true);
      expect(characterCount.text()).toBe('0/20');
    });
  });

  describe('Button Text Input', () => {
    it('should update button text when input changes', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'New Button Text' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('value')).toBe('New Button Text');
    });

    it('should display character count correctly', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'Hello' } });
      wrapper.update();

      const characterCount = wrapper.find('.button-character-count-suffix');
      expect(characterCount.text()).toBe('5/20');
    });

    it('should enforce max length of 20 characters', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      expect(textInput.prop('maxLength')).toBe(20);
    });

    it('should show error when button text is empty', () => {
      mockFormatMessage.mockReturnValue('Button text is required');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      // Set text and then clear it
      inputElement.simulate('change', { target: { value: 'Some text' } });
      wrapper.update();
      inputElement.simulate('change', { target: { value: '' } });
      wrapper.update();

      expect(mockFormatMessage).toHaveBeenCalledWith(messages.buttonTextRequired);
      const updatedInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('error');
    });

    it('should show error when button text is only whitespace', () => {
      mockFormatMessage.mockReturnValue('Button text is required');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: '   ' } });
      wrapper.update();

      expect(mockFormatMessage).toHaveBeenCalledWith(messages.buttonTextRequired);
      const updatedInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('error');
    });

    it('should clear error when valid text is entered after error', () => {
      mockFormatMessage.mockReturnValue('Button text is required');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      // Trigger error
      inputElement.simulate('change', { target: { value: '' } });
      wrapper.update();

      // Enter valid text
      inputElement.simulate('change', { target: { value: 'Valid Text' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });
  });

  describe('Button URL Input', () => {
    it('should update button URL when input changes', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://example.com' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('value')).toBe('https://example.com');
    });

    it('should show error when URL is empty', () => {
      mockFormatMessage.mockReturnValue('Button URL is required');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      // Set URL and then clear it
      inputElement.simulate('change', { target: { value: 'https://example.com' } });
      wrapper.update();
      inputElement.simulate('change', { target: { value: '' } });
      wrapper.update();

      expect(mockFormatMessage).toHaveBeenCalledWith(messages.buttonUrlRequired);
      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('error');
    });

    it('should show error when URL is only whitespace', () => {
      mockFormatMessage.mockReturnValue('Button URL is required');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: '   ' } });
      wrapper.update();

      expect(mockFormatMessage).toHaveBeenCalledWith(messages.buttonUrlRequired);
      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('error');
    });

    it('should show error when URL is invalid', () => {
      mockFormatMessage.mockReturnValue('Please enter a valid URL');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'not-a-valid-url' } });
      wrapper.update();

      expect(mockFormatMessage).toHaveBeenCalledWith(messages.buttonUrlInvalid);
      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('error');
    });

    it('should show error when URL lacks TLD (e.g., https://google)', () => {
      mockFormatMessage.mockReturnValue('Please enter a valid URL');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://google' } });
      wrapper.update();

      expect(mockFormatMessage).toHaveBeenCalledWith(messages.buttonUrlInvalid);
      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('error');
    });

    it('should accept valid HTTP URL', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'http://example.com' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid HTTPS URL', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://example.com' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid URL with www', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://www.example.com' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid URL with path and query parameters', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', {
        target: { value: 'https://example.com/path?param=value&other=123' },
      });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid URL with long gTLD (.company)', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://example.company' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid URL with long gTLD (.technology)', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://example.technology' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid URL with long gTLD (.international)', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://example.international' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid URL with long gTLD and www prefix', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://www.example.company' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should accept valid URL with long gTLD and path', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      inputElement.simulate('change', { target: { value: 'https://example.technology/path/to/page' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });

    it('should clear error when valid URL is entered after error', () => {
      mockFormatMessage.mockReturnValue('Please enter a valid URL');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      // Trigger error with invalid URL
      inputElement.simulate('change', { target: { value: 'invalid-url' } });
      wrapper.update();

      // Enter valid URL
      inputElement.simulate('change', { target: { value: 'https://example.com' } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('status')).toBe('');
    });
  });

  describe('Save Button', () => {
    it('should be disabled when button text is empty', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const saveButton = wrapper.find('.button-form-save').find('CapButton').first();

      expect(saveButton.prop('disabled')).toBe(true);
    });

    it('should be disabled when button URL is empty', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const saveButton = wrapper.find('.button-form-save').find('CapButton').first();

      inputElement.simulate('change', { target: { value: 'Button Text' } });
      wrapper.update();

      expect(saveButton.prop('disabled')).toBe(true);
    });

    it('should be disabled when button text has error', () => {
      mockFormatMessage.mockReturnValue('Button text is required');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const urlInputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      const saveButton = wrapper.find('.button-form-save').find('CapButton').first();

      urlInputElement.simulate('change', { target: { value: 'https://example.com' } });
      textInputElement.simulate('change', { target: { value: '' } });
      wrapper.update();

      expect(saveButton.prop('disabled')).toBe(true);
    });

    it('should be disabled when button URL has error', () => {
      mockFormatMessage.mockReturnValue('Please enter a valid URL');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const urlInputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      const saveButton = wrapper.find('.button-form-save').find('CapButton').first();

      textInputElement.simulate('change', { target: { value: 'Button Text' } });
      urlInputElement.simulate('change', { target: { value: 'invalid-url' } });
      wrapper.update();

      expect(saveButton.prop('disabled')).toBe(true);
    });

    it('should be enabled when both text and URL are valid', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const urlInputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      textInputElement.simulate('change', { target: { value: 'Button Text' } });
      urlInputElement.simulate('change', { target: { value: 'https://example.com' } });
      wrapper.update();

      // Re-find the save button after state updates to get fresh props
      const saveButton = wrapper.find('.button-form-save').find('CapButton').first();
      // CapButton may return empty string or false when disabled is false, so check for falsiness
      expect(saveButton.prop('disabled')).toBeFalsy();
    });

    it('should call onSave with trimmed values when save is clicked', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const urlInputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      textInputElement.simulate('change', { target: { value: '  Button Text  ' } });
      urlInputElement.simulate('change', { target: { value: '  https://example.com  ' } });
      wrapper.update();

      // Re-find the save button after state updates to get fresh props
      const saveButton = wrapper.find('.button-form-save').find('CapButton').first();
      saveButton.prop('onClick')();

      expect(mockOnSave).toHaveBeenCalledWith({
        text: 'Button Text',
        url: 'https://example.com',
        type: 'primary',
      });
    });

    it('should not call onSave when validation fails', () => {
      mockFormatMessage.mockReturnValue('Button text is required');
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const urlInputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      const saveButton = wrapper.find('.button-form-save').find('CapButton').first();

      textInputElement.simulate('change', { target: { value: '' } });
      urlInputElement.simulate('change', { target: { value: 'https://example.com' } });
      wrapper.update();

      // Save button should be disabled, so clicking it won't trigger onSave
      // Even if we simulate the click, validation should prevent onSave from being called
      expect(saveButton.prop('disabled')).toBe(true);
      expect(mockOnSave).not.toHaveBeenCalled();
    });

    it('should trigger save on Enter key when form is valid', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const urlInputElement = findInputElement(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);
      const form = wrapper.find('.webpush-button-form').hostNodes().first();

      textInputElement.simulate('change', { target: { value: 'Button Text' } });
      urlInputElement.simulate('change', { target: { value: 'https://example.com' } });
      wrapper.update();

      form.simulate('keyDown', { key: 'Enter' });

      expect(mockOnSave).toHaveBeenCalledWith({
        text: 'Button Text',
        url: 'https://example.com',
        type: 'primary',
      });
    });

    it('should not trigger save on Enter key when form is invalid', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const form = wrapper.find('.webpush-button-form').hostNodes().first();

      form.simulate('keyDown', { key: 'Enter' });

      expect(mockOnSave).not.toHaveBeenCalled();
    });
  });

  describe('Cancel Button', () => {
    it('should call onCancel when cancel button is clicked', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const cancelButton = wrapper.find('.button-form-cancel').find('CapButton').first();

      cancelButton.prop('onClick')();

      expect(mockOnCancel).toHaveBeenCalled();
    });

    it('should show "Delete" text when not in edit mode', () => {
      const wrapper = shallowWithIntl(<ButtonForm {...defaultProps} isEditMode={false} />);
      expect(wrapper).toMatchSnapshot();
    });

    it('should show "Cancel" text when in edit mode', () => {
      const wrapper = shallowWithIntl(<ButtonForm {...defaultProps} isEditMode={true} />);
      expect(wrapper).toMatchSnapshot();
    });
  });

  describe('Initial Data', () => {
    it('should initialize with provided button text', () => {
      const initialData = {
        text: 'Initial Text',
        url: 'https://initial.com',
      };
      const wrapper = mountWithIntl(
        <ButtonForm {...defaultProps} initialData={initialData} />
      );
      const textInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      expect(textInput.prop('value')).toBe('Initial Text');
    });

    it('should initialize with provided button URL', () => {
      const initialData = {
        text: 'Initial Text',
        url: 'https://initial.com',
      };
      const wrapper = mountWithIntl(
        <ButtonForm {...defaultProps} initialData={initialData} />
      );
      const urlInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      expect(urlInput.prop('value')).toBe('https://initial.com');
    });

    it('should handle empty initial data', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} initialData={null} />);
      const textInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const urlInput = findCapInputById(wrapper, `webpush-button-url-input-${defaultProps.buttonType}`);

      expect(textInput.prop('value')).toBe('');
      expect(urlInput.prop('value')).toBe('');
    });
  });

  describe('Max Length', () => {
    it('should display correct character count at max length', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      const maxLengthText = 'A'.repeat(20);
      inputElement.simulate('change', { target: { value: maxLengthText } });
      wrapper.update();

      const characterCount = wrapper.find('.button-character-count-suffix');
      expect(characterCount.text()).toBe('20/20');
    });

    it('should prevent input beyond max length', () => {
      const wrapper = mountWithIntl(<ButtonForm {...defaultProps} />);
      const textInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      const inputElement = findInputElement(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);

      expect(textInput.prop('maxLength')).toBe(20);

      const maxLengthText = 'A'.repeat(20);
      inputElement.simulate('change', { target: { value: maxLengthText } });
      wrapper.update();

      const updatedInput = findCapInputById(wrapper, `webpush-button-text-input-${defaultProps.buttonType}`);
      expect(updatedInput.prop('value').length).toBe(20);
    });
  });
});
