import * as React from 'react';
import { mount } from 'enzyme';
import expect from 'expect';
import { spy } from 'sinon';

import { TrackingProvider } from 'mweb/common/tracking/trackingProvider';
import { extendInteractionMedium } from 'mweb/common/tracking/extendInteractionMedium';
import { withTracking, TrackingProps } from 'mweb/common/tracking/withTracking';

describe('<TrackingProvider /> & withClickTracking', () => {
  it('gets interaction payload with blank medium from context', () => {
    const TestElement = withTracking((props: TrackingProps): JSX.Element => (
      <div
        id="test-element"
        onClick={props.trackClick({
          interactionContent: 'content',
          interactionTargetPath: '/path',
        })}
      />
    ));

    const trackingTrackClick = spy();
    const provider = mount(
      <TrackingProvider trackingTrackClick={trackingTrackClick}>
        <TestElement />
      </TrackingProvider>,
    );
    provider.find('#test-element').simulate('click');
    expect(trackingTrackClick.getCall(0).args[0]).toEqual({
      interactionMedium: '',
      interactionContent: 'content',
      interactionTargetPath: '/path',
    });
  });

  it('calls trackClick callback on click when provided', () => {
    const callback = spy();
    const TestElement = withTracking((props: TrackingProps) => (
      <div
        id="test-element"
        onClick={props.trackClick({ interactionContent: 'content' }, callback)}
      />
    ));

    const provider = mount(
      <TrackingProvider trackingTrackClick={() => undefined}>
        <TestElement />
      </TrackingProvider>,
    );
    expect(callback.called).toEqual(false);
    provider.find('#test-element').simulate('click');
    expect(callback.called).toEqual(true);
  });

  describe('extendInteractionMedium', () => {
    it('medium gets set when given a string', () => {
      const TestElement = withTracking((props: TrackingProps) => (
        <div
          id="test-element"
          onClick={props.trackClick({ interactionContent: 'content' })}
        />
      ));

      const TestIntermediateElement = extendInteractionMedium(
        (props: { children?: React.ReactNode }) => <div>{props.children}</div>,
        'intermediate',
      );

      const trackingTrackClick = spy();
      const provider = mount(
        <TrackingProvider trackingTrackClick={trackingTrackClick}>
          <TestIntermediateElement>
            <TestElement />
          </TestIntermediateElement>
        </TrackingProvider>,
      );
      provider.find('#test-element').simulate('click');
      expect(trackingTrackClick.getCall(0).args[0]).toEqual({
        interactionMedium: 'intermediate',
        interactionContent: 'content',
      });
    });

    it('medium gets set when given a function', () => {
      const TestElement = withTracking((props: TrackingProps) => (
        <div
          id="test-element"
          onClick={props.trackClick({ interactionContent: 'content' })}
        />
      ));

      interface TestProps {
        children?: React.ReactNode;
        test: string;
      }

      const TestIntermediateElement = extendInteractionMedium(
        (props: TestProps) => <div>{props.children}</div>,
        (props: TestProps) => props.test,
      );

      const trackingTrackClick = spy();
      const provider = mount(
        <TrackingProvider trackingTrackClick={trackingTrackClick}>
          <TestIntermediateElement test="between">
            <TestElement />
          </TestIntermediateElement>
        </TrackingProvider>,
      );
      provider.find('#test-element').simulate('click');
      expect(trackingTrackClick.getCall(0).args[0]).toEqual({
        interactionMedium: 'between',
        interactionContent: 'content',
      });
    });

    it('medium gets extended when more than blank default in context', () => {
      const TestElement = withTracking((props: TrackingProps) => (
        <div
          id="test-element"
          onClick={props.trackClick({ interactionContent: 'content' })}
        />
      ));

      interface TestProps {
        children?: React.ReactNode;
        test: string;
      }

      const TestIntermediateElement = extendInteractionMedium(
        (props: TestProps) => <div>{props.children}</div>,
        (props: TestProps) => props.test,
      );

      const trackingTrackClick = spy();
      const provider = mount(
        <TrackingProvider trackingTrackClick={trackingTrackClick}>
          <TestIntermediateElement test="start">
            <TestIntermediateElement test="finish">
              <TestElement />
            </TestIntermediateElement>
          </TestIntermediateElement>
        </TrackingProvider>,
      );
      provider.find('#test-element').simulate('click');
      expect(trackingTrackClick.getCall(0).args[0]).toEqual({
        interactionMedium: 'start.finish',
        interactionContent: 'content',
      });
    });
  });
});
