import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import Helmet from 'react-helmet';
import { defineMessages, injectIntl, InjectedIntl } from 'react-intl';
import { RouteComponentProps } from 'react-router-dom';

import { channelDirectoryPageTransition } from 'mweb/common/actions/pages/channelDirectory';
import { channelsDataGetPage } from 'mweb/common/actions/data/channels';
import { ChannelList } from 'mweb/common/components/channelList';
import { statusSuccess, RootState } from 'mweb/common/reducers/root';
import {
  ChannelDetails,
  ALL_CHANNELS,
} from 'mweb/common/reducers/data/channels';
import { GameDetails } from 'mweb/common/reducers/data/games';
import InitialLoadWrapper, {
  InitialLoadWrapperProps,
} from 'mweb/common/components/initialLoadWrapper';
import {
  ErrorStatableOwnProps,
  ErrorStateWrapper,
} from 'mweb/common/components/errors/errorStateWrapper';
import { withLatencyTracker } from 'mweb/common/latency/withLatencyTracker';
import {
  getCurrentGameForChannelDirectory,
  channelDirectoryIsLoaded,
  channelDirectoryChannelList,
} from 'mweb/common/selectors/pages/channelDirectory';
import { BranchUpsellExperiment } from 'mweb/common/components/branchUpsell';
import { ClientOnly } from 'mweb/common/containers/clientOnly';
import { BranchJourneyType } from 'branch-io';

const messages = defineMessages({
  singleGameDirectory: {
    id: 'channel-directory--game-title',
    defaultMessage: '{game} - Watch Live Streams on Twitch',
  },
  allGamesDirectory: {
    id: 'channel-directory--all-games-title',
    defaultMessage: 'Watch the Top Live Streams on Twitch',
  },
});

export interface ChannelDirectoryStateProps {
  channels: ChannelDetails[];
  isLoading: boolean;
  game: GameDetails | undefined;
}

export interface ChannelDirectoryDispatchProps {
  transitionToTargetGame: (game: string) => void;
  getNextPage: (gameAlias: string) => void;
}

export interface ChannelDirectoryMatchParams {
  gameAlias: string | undefined;
}

export interface ChannelDirectoryOwnProps
  extends RouteComponentProps<ChannelDirectoryMatchParams> {}

export interface ChannelDirectoryProps
  extends ChannelDirectoryStateProps,
    ChannelDirectoryDispatchProps,
    ChannelDirectoryOwnProps {
  intl: InjectedIntl;
}

class ChannelDirectoryBase extends React.Component<ChannelDirectoryProps, {}> {
  static displayName: string = 'ChannelDirectory';

  isInteractive(): boolean {
    return !this.props.isLoading;
  }

  componentDidMount(): void {
    this.props.transitionToTargetGame(this.gameName());
  }

  gameName(): string {
    if (!this.props.match.params.gameAlias) {
      return ALL_CHANNELS;
    }

    return this.props.game
      ? this.props.game.name
      : this.props.match.params.gameAlias;
  }

  gameDisplayName(): string | undefined {
    return this.props.game
      ? this.props.game.displayName
      : this.props.match.params.gameAlias;
  }

  title(): string {
    if (this.props.match.params.gameAlias) {
      return this.props.intl.formatMessage(messages.singleGameDirectory, {
        // the above if gate ensures that this function will not return undefined
        game: this.gameDisplayName()!,
      });
    } else {
      return this.props.intl.formatMessage(messages.allGamesDirectory);
    }
  }

  render(): JSX.Element {
    return (
      <div>
        <Helmet>
          <title>{this.title()}</title>
        </Helmet>
        <ChannelList
          channels={this.props.channels}
          gameDisplayName={this.gameDisplayName()}
          getNextPage={this.props.getNextPage.bind(undefined, this.gameName())}
        />
        {this.props.match.params.gameAlias && (
          <ClientOnly>
            <BranchUpsellExperiment
              delaySecondsUntilUpsell={5}
              journey={{
                type: BranchJourneyType.GameDir,
                game: this.gameDisplayName() || this.gameName(),
              }}
            />
          </ClientOnly>
        )}
      </div>
    );
  }
}

interface ChannelDirectoryMapStateProps
  extends ChannelDirectoryStateProps,
    InitialLoadWrapperProps,
    ErrorStatableOwnProps {}

function mapStateToProps(state: RootState): ChannelDirectoryMapStateProps {
  return {
    game: getCurrentGameForChannelDirectory(state),
    channels: channelDirectoryChannelList(state),
    isLoading: !channelDirectoryIsLoaded(state),
    internalError: !statusSuccess(state),
  };
}

function mapDispatchToProps(
  dispatch: Dispatch<RootState>,
): ChannelDirectoryDispatchProps {
  return bindActionCreators(
    {
      transitionToTargetGame: channelDirectoryPageTransition,
      getNextPage: channelsDataGetPage,
    },
    dispatch,
  );
}

export const ChannelDirectory = connect(mapStateToProps, mapDispatchToProps)(
  ErrorStateWrapper(
    injectIntl(InitialLoadWrapper(withLatencyTracker(ChannelDirectoryBase))),
  ),
) as React.ComponentClass<ChannelDirectoryOwnProps>;
