import sortBy from 'lodash/sortBy';

import {mountGlobalModal} from 'sentry-test/modal';

import {openModal} from 'sentry/actionCreators/modal';
import {convertRelayPiiConfig} from 'sentry/views/settings/components/dataScrubbing/convertRelayPiiConfig';
import Edit from 'sentry/views/settings/components/dataScrubbing/modals/edit';
import submitRules from 'sentry/views/settings/components/dataScrubbing/submitRules';
import {MethodType, RuleType} from 'sentry/views/settings/components/dataScrubbing/types';
import {
  getMethodLabel,
  getRuleLabel,
  valueSuggestions,
} from 'sentry/views/settings/components/dataScrubbing/utils';

const relayPiiConfig = TestStubs.DataScrubbingRelayPiiConfig();
const stringRelayPiiConfig = JSON.stringify(relayPiiConfig);
const organizationSlug = 'sentry';
const convertedRules = convertRelayPiiConfig(stringRelayPiiConfig);
const rules = convertedRules;
const rule = rules[2];
const successfullySaved = jest.fn();
const projectId = 'foo';
const endpoint = `/projects/${organizationSlug}/${projectId}/`;
const api = new MockApiClient();

jest.mock('sentry/views/settings/components/dataScrubbing/submitRules');

async function renderComponent() {
  const modal = await mountGlobalModal();

  openModal(modalProps => (
    <Edit
      {...modalProps}
      projectId={projectId}
      savedRules={rules}
      api={api}
      endpoint={endpoint}
      orgSlug={organizationSlug}
      onSubmitSuccess={successfullySaved}
      rule={rule}
    />
  ));

  await tick();
  modal.update();

  return modal;
}

describe('Edit Modal', () => {
  it('open Edit Rule Modal', async () => {
    const wrapper = await renderComponent();

    expect(wrapper.find('Header').text()).toEqual('Edit an advanced data scrubbing rule');

    const fieldGroup = wrapper.find('FieldGroup');
    expect(fieldGroup).toHaveLength(2);

    // Method Field
    const methodGroup = fieldGroup.at(0).find('Field');
    const methodField = methodGroup.at(0);
    expect(methodField.find('FieldLabel').text()).toEqual('Method');
    const methodFieldHelp = 'What to do';
    expect(methodField.find('QuestionTooltip').prop('title')).toEqual(methodFieldHelp);
    expect(methodField.find('Tooltip').prop('title')).toEqual(methodFieldHelp);
    const methodFieldSelect = methodField.find('SelectField');
    expect(methodFieldSelect.exists()).toBe(true);
    const methodFieldSelectProps = methodFieldSelect.props();
    expect(methodFieldSelectProps.value).toEqual(MethodType.REPLACE);
    const methodFieldSelectOptions = sortBy(Object.values(MethodType)).map(value => ({
      ...getMethodLabel(value),
      value,
    }));
    expect(methodFieldSelectProps.options).toEqual(methodFieldSelectOptions);

    // Placeholder Field
    const placeholderField = methodGroup.at(1);
    expect(placeholderField.find('FieldLabel').text()).toEqual(
      'Custom Placeholder (Optional)'
    );
    const placeholderFieldHelp = 'It will replace the default placeholder [Filtered]';
    expect(placeholderField.find('QuestionTooltip').prop('title')).toEqual(
      placeholderFieldHelp
    );
    expect(placeholderField.find('Tooltip').prop('title')).toEqual(placeholderFieldHelp);

    if (rule.method === MethodType.REPLACE) {
      const placeholderInput = placeholderField.find('input');
      expect(placeholderInput.prop('value')).toEqual(rule.placeholder);
    }

    // Type Field
    const typeGroup = fieldGroup.at(1).find('Field');
    const typeField = typeGroup.at(0);
    expect(typeField.find('FieldLabel').text()).toEqual('Data Type');
    const typeFieldHelp =
      'What to look for. Use an existing pattern or define your own using regular expressions.';
    expect(typeField.find('QuestionTooltip').prop('title')).toEqual(typeFieldHelp);
    expect(typeField.find('Tooltip').prop('title')).toEqual(typeFieldHelp);
    const typeFieldSelect = typeField.find('SelectField');
    expect(typeFieldSelect.exists()).toBe(true);
    const typeFieldSelectProps = typeFieldSelect.props();
    expect(typeFieldSelectProps.value).toEqual(RuleType.PATTERN);

    const typeFieldSelectOptions = sortBy(Object.values(RuleType)).map(value => ({
      label: getRuleLabel(value),
      value,
    }));
    expect(typeFieldSelectProps.options).toEqual(typeFieldSelectOptions);

    // Regex matches Field
    const regexField = typeGroup.at(1);
    expect(regexField.find('FieldLabel').text()).toEqual('Regex matches');
    const regexFieldHelp = 'Custom regular expression (see documentation)';
    expect(regexField.find('QuestionTooltip').prop('title')).toEqual(regexFieldHelp);
    expect(regexField.find('Tooltip').prop('title')).toEqual(regexFieldHelp);

    if (rule.type === RuleType.PATTERN) {
      const regexFieldInput = regexField.find('input');
      expect(regexFieldInput.prop('value')).toEqual(rule.pattern);
    }

    // Event ID
    expect(wrapper.find('Toggle').text()).toEqual('Use event ID for auto-completion');

    // Source Field
    const sourceGroup = wrapper.find('SourceGroup');
    expect(sourceGroup.exists()).toBe(true);
    expect(sourceGroup.find('EventIdField')).toHaveLength(0);
    const sourceField = sourceGroup.find('Field');
    expect(sourceField.find('FieldLabel').text()).toEqual('Source');
    const sourceFieldHelp =
      'Where to look. In the simplest case this can be an attribute name.';
    expect(sourceField.find('QuestionTooltip').prop('title')).toEqual(sourceFieldHelp);
    expect(sourceField.find('Tooltip').prop('title')).toEqual(sourceFieldHelp);
    const sourceFieldInput = sourceField.find('input');
    expect(sourceFieldInput.prop('value')).toEqual(rule.source);

    // Close Modal
    const cancelButton = wrapper.find('[aria-label="Cancel"]').hostNodes();
    expect(cancelButton.exists()).toBe(true);
    cancelButton.simulate('click');

    await tick();
    wrapper.update();

    expect(wrapper.find('GlobalModal[visible=true]').exists()).toBe(false);
  });

  it('edit Rule Modal', async () => {
    const wrapper = await renderComponent();

    // Method Field
    const methodField = wrapper.find('[data-test-id="method-field"]');
    const methodFieldInput = methodField.find('input').at(0);
    methodFieldInput.simulate('keyDown', {key: 'ArrowDown'});
    const methodFieldMenuOptions = wrapper.find(
      '[data-test-id="method-field"] MenuList Option'
    );
    const maskOption = methodFieldMenuOptions.at(1);
    maskOption.simulate('click');

    // Placeholder Field should be now hidden
    const placeholderField = wrapper.find('[data-test-id="placeholder-field"]');
    expect(placeholderField).toHaveLength(0);

    // Type Field
    const typeField = wrapper.find('[data-test-id="type-field"]');
    const typeFieldInput = typeField.find('input').at(0);
    typeFieldInput.simulate('keyDown', {key: 'ArrowDown'});
    const typeFieldMenuOptions = wrapper.find(
      '[data-test-id="type-field"] MenuList Option'
    );
    const anythingOption = typeFieldMenuOptions.at(0);
    anythingOption.simulate('click');

    // Regex Field should be now hidden
    const regexField = wrapper.find('[data-test-id="regex-field"]');
    expect(regexField).toHaveLength(0);

    // Source Field
    const sourceField = wrapper.find('[data-test-id="source-field"]');
    const sourceFieldInput = sourceField.find('input');
    sourceFieldInput.simulate('change', {target: {value: valueSuggestions[2].value}});

    // Save rule
    const saveButton = wrapper.find('[aria-label="Save Rule"]').hostNodes();
    expect(saveButton.exists()).toBe(true);
    saveButton.simulate('click');

    expect(submitRules).toHaveBeenCalled();
    expect(submitRules).toHaveBeenCalledWith(api, endpoint, [
      {
        id: 0,
        method: 'replace',
        type: 'password',
        source: 'password',
        placeholder: 'Scrubbed',
      },
      {id: 1, method: 'mask', type: 'creditcard', source: '$message'},
      {
        id: 2,
        method: 'mask',
        pattern: '',
        placeholder: '',
        type: 'anything',
        source: '$error.value',
      },
    ]);
  });
});
