import expect from 'expect';
import { stub, SinonStub } from 'sinon';
import { InjectedIntl, FormattedMessage } from 'react-intl';
import {
  ButtonIcon,
  ChannelStatusIndicator,
  ChannelStatusIndicatorStatus,
  Stat,
  SVGAsset,
  Text,
} from 'twitch-core-ui';

import { partialPropShallowWrapper } from 'mtest/helpers/partialPropWrappers';
import { VOD_HIGHLIGHT_DETAILS } from 'mtest/fetchMocks/vods';
import { CLIP_DETAILS } from 'mtest/fetchMocks/clips';
import { trackClickMock, testClickTracking } from 'mtest/helpers/tracking';

import {
  ChannelInfoCardBase as ChannelInfoCard,
  ChannelInfoCardProps,
  INTERACTION_CONTENT_LIVE_CHANNEL_LINK,
  INTERACTION_CONTENT_EXPAND,
  INTERACTION_CONTENT_MOST_POPULAR,
} from 'mweb/common/components/channelInfoCard';
import { ChannelOnlineStatus } from 'mweb/common/reducers/data/channels';
import { buildChannelPath } from 'mweb/common/utils/pathBuilders';
import { TrackClickHandler } from 'mweb/common/tracking/withTracking';
import { buildPathForBaseVideo } from 'mweb/common/utils/pathBuilders';
import VideoCard from 'mweb/common/components/videoCard';
import { TrackedLink } from 'mweb/common/tracking/trackedLink';

describe('<ChannelInfoCard />', () => {
  const DEFAULT_PROPS: ChannelInfoCardProps = {
    bannerImageURL: '//banner.img',
    description: 'I am infrequently used',
    displayName: 'Voxel',
    followerCount: undefined,
    lifetimeViewerCount: undefined,
    logoURL: '//logo.img',
    name: 'voxel',
    onlineStatus: ChannelOnlineStatus.Offline,
    trackClick: trackClickMock(),
    video: undefined,
    intl: ({
      formatNumber: stub().returnsArg(0),
      formatMessage: stub().returns('Text'),
    } as any) as InjectedIntl,
  };

  const subject = partialPropShallowWrapper(ChannelInfoCard, DEFAULT_PROPS);

  it('renders the component when not given follower and viewer counts', () => {
    const card = subject();

    expect(
      card.find('.mw-channel-info-card__banner').prop('style')!.backgroundImage,
    ).toEqual(`url(${DEFAULT_PROPS.bannerImageURL})`);

    const body = card.find('.mw-channel-info-card__body');

    const avatar = body.find('.mw-channel-info-card__avatar__image');
    expect(avatar.prop('alt')).toEqual(DEFAULT_PROPS.displayName);
    expect(avatar.prop('src')).toEqual(DEFAULT_PROPS.logoURL);

    const content = body.childAt(1);
    expect(
      content
        .find(Text)
        .first()
        .childAt(0)
        .text(),
    ).toEqual(DEFAULT_PROPS.displayName);
  });

  describe('follower and viewer stats', () => {
    it('do not render if not provided values', () => {
      const content = subject()
        .find('.mw-channel-info-card__body')
        .childAt(1);
      expect(content).toNotContain(Stat);
    });

    it('render when given values', () => {
      const FOLLOWERS = 123;
      const VIEWERS = 456;
      const content = subject({
        followerCount: FOLLOWERS,
        lifetimeViewerCount: VIEWERS,
      })
        .find('.mw-channel-info-card__body')
        .childAt(1);

      expect(
        content
          .find(Stat)
          .first()
          .prop('icon'),
      ).toEqual(SVGAsset.GlyphFollowers);
      expect(
        (DEFAULT_PROPS.intl.formatMessage as SinonStub).getCall(0).args[0].id,
      ).toEqual('followers');

      expect(
        content
          .find(Stat)
          .last()
          .prop('icon'),
      ).toEqual(SVGAsset.GlyphViews);
      expect(
        (DEFAULT_PROPS.intl.formatMessage as SinonStub).getCall(1).args[0].id,
      ).toEqual('views');

      expect(
        content
          .find(Stat)
          .first()
          .prop('value'),
      ).toEqual(FOLLOWERS);
      expect(
        content
          .find(Stat)
          .last()
          .prop('value'),
      ).toEqual(VIEWERS);
    });
  });

  it('renders the proper text in the description', () => {
    expect(
      subject()
        .find('.mw-channel-info-card__details')
        .find(Text)
        .first()
        .childAt(0)
        .text(),
    ).toEqual(DEFAULT_PROPS.description);
  });

  it('toggles the expanded content properly', () => {
    const card = subject();
    const button = card.find(ButtonIcon);

    expect(card.find('.mw-channel-info-card__details')).toNotHaveClass(
      'mw-channel-info-card__details--visible',
    );

    button.simulate('click');

    expect(card.find('.mw-channel-info-card__details')).toHaveClass(
      'mw-channel-info-card__details--visible',
    );

    button.simulate('click');

    expect(card.find('.mw-channel-info-card__details')).toNotHaveClass(
      'mw-channel-info-card__details--visible',
    );
  });

  describe('online status', () => {
    it('does not show link nor live indicator when channel is offline', () => {
      const body = subject().find('.mw-channel-info-card__body');

      expect(body.find(TrackedLink).length).toEqual(0);
      expect(body.find(ChannelStatusIndicator).length).toEqual(0);
    });

    it('show links and live indicator when channel is online', () => {
      const body = subject({ onlineStatus: ChannelOnlineStatus.Online }).find(
        '.mw-channel-info-card__body',
      );

      const link = body.find(TrackedLink);
      expect(link.prop('to')).toEqual(buildChannelPath(DEFAULT_PROPS.name));
      expect(link.find(ChannelStatusIndicator).prop('pulse')).toEqual(true);
      expect(link.find(ChannelStatusIndicator).prop('status')).toEqual(
        ChannelStatusIndicatorStatus.Live,
      );
      expect(link.find(FormattedMessage).prop('id')).toEqual('channel-is-live');
    });
  });

  describe('most popular video', () => {
    it('does not render a VideoCard if none provided ', () => {
      const card = subject();
      const videoCard = card.find(VideoCard);
      expect(videoCard).toNotExist();
    });

    it('renders a highlight VideoCard with the proper title if one provided', () => {
      const card = subject({ video: VOD_HIGHLIGHT_DETAILS });
      const videoCard = card.find(VideoCard);
      expect(videoCard).toHaveProps({
        title: VOD_HIGHLIGHT_DETAILS.title,
        interactionContent: INTERACTION_CONTENT_MOST_POPULAR,
        linkTo: buildPathForBaseVideo(VOD_HIGHLIGHT_DETAILS),
      });
      expect(
        card.find('.mw-channel-info-card__details').find(FormattedMessage),
      ).toHaveProp('id', 'most-popular-highlight');
    });

    it('renders a clip VideoCard with the proper title if one provided', () => {
      const card = subject({ video: CLIP_DETAILS });
      const videoCard = card.find(VideoCard);
      expect(videoCard).toHaveProps({
        title: CLIP_DETAILS.title,
        interactionContent: INTERACTION_CONTENT_MOST_POPULAR,
        linkTo: buildPathForBaseVideo(CLIP_DETAILS),
      });
      expect(
        card.find('.mw-channel-info-card__details').find(FormattedMessage),
      ).toHaveProp('id', 'most-popular-clip');
    });
  });

  testClickTracking([
    {
      title: 'tracks clicks on live channel',
      expectedPayload: {
        interactionContent: INTERACTION_CONTENT_LIVE_CHANNEL_LINK,
        interactionTargetPath: buildChannelPath(DEFAULT_PROPS.name),
      },
      clickTargetBuilder: () =>
        subject({ onlineStatus: ChannelOnlineStatus.Online })
          .find('.mw-channel-info-card__body')
          .find(TrackedLink),
    },
    {
      title: 'tracks clicks on expand button',
      expectedPayload: {
        interactionContent: INTERACTION_CONTENT_EXPAND,
      },
      clickTargetBuilder: (trackClick: TrackClickHandler) =>
        subject({ trackClick }).find(ButtonIcon),
    },
  ]);
});
