import { ShallowWrapper } from 'enzyme';
import expect from 'expect';
import faker from 'faker';
import { Text, Avatar } from 'twitch-core-ui';

import { partialPropShallowWrapper } from 'mtest/helpers/partialPropWrappers';
import { trackClickMock, testClickTracking } from 'mtest/helpers/tracking';
import { VOD_DETAILS } from 'mtest/fetchMocks/vods';
import { GAME_1 } from 'mtest/fetchMocks/games';

import {
  EventPanelsProps,
  EventPanels,
  INTERACTION_CONTENT_GAME,
  INTERACTION_CONTENT_CHANNEL,
} from 'mweb/common/components/eventPanels';
import {
  buildChannelDirectoryPathFromDecodedGame,
  buildChannelPath,
} from 'mweb/common/utils/pathBuilders';
import VideoCard from 'mweb/common/components/videoCard';
import { buildVODPath } from 'mweb/common/utils/pathBuilders';
import { TrackClickHandler } from 'mweb/common/tracking/withTracking';

const EVENT: EventPanelsProps = {
  logoURL: faker.image.imageUrl(),
  channelDisplayName: 'Merryweather',
  channelName: 'merryweather',
  trackClick: trackClickMock(),
  game: undefined,
  video: undefined,
};

const EVENT_WITH_GAME: EventPanelsProps = {
  ...EVENT,
  game: GAME_1,
};

const EVENT_WITH_GAME_AND_VOD: EventPanelsProps = {
  ...EVENT_WITH_GAME,
  video: VOD_DETAILS,
};

describe('<EventInfo />', () => {
  describe('with game but no vod', () => {
    const subject = partialPropShallowWrapper(EventPanels, EVENT_WITH_GAME);

    itDisplaysChannelInfo(subject);
    itDisplaysGameInfo(subject);

    it('has no vod info', () => {
      expect(subject().find('.event-vod-info').length).toEqual(0);
    });
  });

  describe('without game or vod', () => {
    const subject = partialPropShallowWrapper(EventPanels, EVENT);

    itDisplaysChannelInfo(subject);

    it('has no game info', () => {
      expect(subject().find('.event-game-info').length).toEqual(0);
    });
    it('has no vod info', () => {
      expect(subject().find('.event-vod-info').length).toEqual(0);
    });
  });

  describe('with game and vod', () => {
    const subject = partialPropShallowWrapper(
      EventPanels,
      EVENT_WITH_GAME_AND_VOD,
    );

    itDisplaysChannelInfo(subject);
    itDisplaysGameInfo(subject);

    it('has vod info', () => {
      expect(subject().find('.event-vod-info').length).toEqual(1);
    });

    describe('.event-vod-info', () => {
      it('passes correct props to video list item', () => {
        const expectedProps = {
          title: VOD_DETAILS.title,
          imageURL: VOD_DETAILS.thumbnailURL,
          gameName: VOD_DETAILS.game,
          viewCount: VOD_DETAILS.viewCount,
          formattedLength: VOD_DETAILS.formattedLength,
          createdAt: VOD_DETAILS.date,
          linkTo: buildVODPath(VOD_DETAILS.id),
          borderTop: false,
          interactionContent: 'vod',
        };
        const videoCard = subject()
          .find('.event-vod-info')
          .find(VideoCard);
        expect(videoCard.props()).toEqual(expectedProps);
      });
    });
  });
});

function itDisplaysChannelInfo(
  subject: (customProps?: DeepPartial<{}>) => ShallowWrapper<{}, {}>,
): void {
  it('has an event info section for channel', () => {
    expect(subject().find('.event-channel-info').length).toEqual(1);
  });

  describe('.event-channel-info', () => {
    const eventChannelInfo = () => subject().find('.event-channel-info');

    it('has a link to the channel', () => {
      expect(
        eventChannelInfo()
          .parent()
          .prop('linkTo'),
      ).toEqual(buildChannelPath(EVENT.channelName));
    });

    it('has the proper text', () => {
      expect(
        eventChannelInfo()
          .find(Text)
          .shallow()
          .text(),
      ).toEqual(EVENT.channelDisplayName);
    });

    describe('the avatar', () => {
      const avatar = eventChannelInfo().find(Avatar);

      it('has the proper alt text', () => {
        expect(avatar.prop('alt')).toEqual(EVENT.channelDisplayName);
      });

      it('has the proper src', () => {
        expect(avatar.prop('src')).toEqual(EVENT.logoURL);
      });
    });
  });

  testClickTracking({
    title: 'tracks clicks on channel info',
    expectedPayload: {
      interactionContent: INTERACTION_CONTENT_CHANNEL,
    },
    clickTargetBuilder: (trackClick: TrackClickHandler) =>
      subject({ trackClick })
        .find('.event-channel-info')
        .parent(),
  });
}

function itDisplaysGameInfo(
  subject: (customProps?: DeepPartial<{}>) => ShallowWrapper<{}, {}>,
): void {
  it('has game info', () => {
    expect(subject().find('.event-game-info').length).toEqual(1);
  });

  describe('.event-game-info', () => {
    const eventGameInfo = () => subject().find('.event-game-info');
    const boxArt = () => eventGameInfo().find('.event-channel-boxart');

    it('includes the game title', () => {
      expect(
        eventGameInfo()
          .find(Text)
          .shallow()
          .text()
          .trim(),
      ).toEqual(EVENT_WITH_GAME.game!.name);
    });

    it('has a link to the game', () => {
      expect(
        eventGameInfo()
          .parent()
          .prop('linkTo'),
      ).toEqual(
        buildChannelDirectoryPathFromDecodedGame(EVENT_WITH_GAME.game!.name),
      );
    });

    it('has an image with proper alt text', () => {
      expect(boxArt()).toHaveProp('alt', EVENT_WITH_GAME.game!.name);
    });

    it('has the proper src', () => {
      expect(boxArt()).toHaveProp('src', EVENT_WITH_GAME.game!.boxArtURL);
    });
  });

  testClickTracking({
    title: 'tracks clicks on game info',
    expectedPayload: {
      interactionContent: INTERACTION_CONTENT_GAME,
    },
    clickTargetTrackingIndex: 1,
    clickTargetBuilder: (trackClick: TrackClickHandler) =>
      subject({ trackClick })
        .find('.event-game-info')
        .parent(),
  });
}
