import expect from 'expect';
import { Location } from 'history';
import { spy, SinonSpy } from 'sinon';
import { Redirect } from 'react-router-dom';

import { partialPropShallowWrapper } from 'mtest/helpers/partialPropWrappers';

import {
  QueryParamCapturer,
  QueryParamCapturerProps,
  QueryParamCapturerCaptureProps,
  QueryParamCapturerParams,
} from 'mweb/common/containers/queryParamCapturer';

const DEFAULT_LOCATION: Location = {
  pathname: '/foo/bar',
  search: '',
  state: {},
  hash: '',
  key: '',
};

const DEFAULT_PROPS: QueryParamCapturerProps = {
  location: DEFAULT_LOCATION,
  captureTrackingParams: () => undefined,
  captureLiveToVODParams: () => undefined,
};

const subject = partialPropShallowWrapper(QueryParamCapturer, DEFAULT_PROPS, {
  disableLifecycleMethods: true,
});

describe('<QueryParamCapturer/>', () => {
  it('does not redirect when none of the target params are present', () => {
    const location = {
      ...DEFAULT_LOCATION,
      search: '?fancy=true',
    };
    expect(subject({ location }).find('Redirect').length).toEqual(0);
  });

  describe('calls proper callback when given with proper payload and redirects with empty string for full matches', () => {
    interface CaptureParamsTestCallback {
      expectedCallback: keyof QueryParamCapturerCaptureProps;
      expectedPayload: QueryParamCapturerParams;
    }

    interface CaptureParamsTest {
      queryString: string;
      expectedCallbacks: CaptureParamsTestCallback[];
    }

    const tests: CaptureParamsTest[] = [
      {
        queryString: '?tt_content=fragile',
        expectedCallbacks: [
          {
            expectedCallback: 'captureTrackingParams',
            expectedPayload: { tt_content: 'fragile', tt_medium: undefined },
          },
        ],
      },
      {
        queryString: '?tt_medium=large',
        expectedCallbacks: [
          {
            expectedCallback: 'captureTrackingParams',
            expectedPayload: { tt_content: undefined, tt_medium: 'large' },
          },
        ],
      },
      {
        queryString: '?tt_medium=grande&tt_content=hot',
        expectedCallbacks: [
          {
            expectedCallback: 'captureTrackingParams',
            expectedPayload: { tt_content: 'hot', tt_medium: 'grande' },
          },
        ],
      },
      {
        queryString: '?stream_id=1234',
        expectedCallbacks: [
          {
            expectedCallback: 'captureLiveToVODParams',
            expectedPayload: { stream_id: '1234' },
          },
        ],
      },
      {
        queryString: '?stream_id=1234&tt_medium=large',
        expectedCallbacks: [
          {
            expectedCallback: 'captureLiveToVODParams',
            expectedPayload: { stream_id: '1234' },
          },
          {
            expectedCallback: 'captureTrackingParams',
            expectedPayload: { tt_content: undefined, tt_medium: 'large' },
          },
        ],
      },
      {
        queryString: '?desktop-redirect=woah',
        expectedCallbacks: [],
      },
    ];

    tests.forEach(({ queryString, expectedCallbacks }) => {
      it(`when query string is ${queryString}`, () => {
        const location = {
          ...DEFAULT_LOCATION,
          search: queryString,
        };

        const callbackProps: Record<
          keyof QueryParamCapturerCaptureProps,
          SinonSpy
        > = {
          captureTrackingParams: spy(),
          captureLiveToVODParams: spy(),
        };

        const component = subject({
          ...callbackProps,
          location,
        });

        expectedCallbacks.forEach(({ expectedCallback, expectedPayload }) => {
          expect(callbackProps[expectedCallback].called).toEqual(true);
          expect(callbackProps[expectedCallback].getCall(0).args[0]).toEqual(
            expectedPayload,
          );
        });

        const redir = component.find(Redirect);
        expect(redir.length).toEqual(1);
        expect(redir.prop('to')).toEqual({
          pathname: location.pathname,
          search: '',
        });
      });
    });
  });

  describe('when extra query params are provided', () => {
    it('redirects to the path with the additional params', () => {
      const location = {
        ...DEFAULT_LOCATION,
        search:
          '?itDoesNotChopFromBeginning=yep&tt_medium=grande&middle_thing=also&tt_content=hot&stream_id=8675309&thisWorks=true',
      };
      const redir = subject({ location }).find(Redirect);
      expect(redir.length).toEqual(1);
      expect(redir.prop('to')).toEqual({
        pathname: location.pathname,
        search:
          'itDoesNotChopFromBeginning=yep&middle_thing=also&thisWorks=true',
      });
    });
  });
});
