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

import { ChannelVideoPlayer } from 'mweb/common/components/videoPlayer/channel';
import InfoBox from 'mweb/common/components/infoBox';
import { ChannelViewerBottomPane } from 'mweb/common/components/channelViewerBottomPane';
import {
  statusNotFound,
  statusInternalError,
  isChatReady,
  RootState,
} from 'mweb/common/reducers/root';
import { getChannelDetails } from 'mweb/common/selectors/data/channels';
import { navigationDeclineMobileWebExperience } from 'mweb/common/actions/navigation';
import {
  channelViewerPageTransition,
  channelViewerCheckLiveToVODStatus,
} from 'mweb/common/actions/pages/channelViewer';
import { ChatEvent } from 'mweb/chat/events/baseChatEvent';
import {
  ErrorStatableOwnProps,
  ErrorStateWrapper,
} from 'mweb/common/components/errors/errorStateWrapper';
import { ClientOnly } from 'mweb/common/containers/clientOnly';
import { withLatencyTracker } from 'mweb/common/latency/withLatencyTracker';
import { BranchUpsellExperiment } from 'mweb/common/components/branchUpsell';
import { BranchTimedTrackerExperiment } from 'mweb/common/components/branchTimedTracker';
import { BranchJourneyType, BranchEvent } from 'branch-io';

if (process.env.BROWSER) {
  require('./channelViewer.sass');
}

export interface ChannelViewerStateProps {
  liveToVODStreamID: string | undefined;
  liveToVODTargetVODid: string;
  channelDisplayName: string | undefined;
  channelID: string | undefined;
  logoUrl: string | undefined;
  game: string | undefined;
  hostedChannel: string | undefined;
  hostedChannelDisplayName: string | undefined;
  chatMessages: ReadonlyArray<ChatEvent>;
  showChat: boolean | undefined;
  sessionID: string;
  isChatReady: boolean;
}

export interface ChannelViewerDispatchProps {
  transitionToTargetChannel: (channel: string) => void;
  checkLiveToVODStatus: (channelID: string, streamID: string) => void;
  switchToDesktop: React.EventHandler<React.MouseEvent<HTMLAnchorElement>>;
}

export interface ChannelViewerMatchParams {
  channel: string;
}

export interface ChannelViewerOwnProps
  extends RouteComponentProps<ChannelViewerMatchParams> {}

export interface ChannelViewerProps
  extends ChannelViewerStateProps,
    ChannelViewerDispatchProps,
    ChannelViewerOwnProps {}

export class ChannelViewer extends React.Component<ChannelViewerProps, {}> {
  static displayName: string = 'ChannelViewer';

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

  componentDidMount(): void {
    this.props.transitionToTargetChannel(this.props.match.params.channel);
  }

  componentDidUpdate(prevProps: ChannelViewerProps): void {
    if (this.props.liveToVODStreamID && this.props.channelID) {
      this.props.checkLiveToVODStatus(
        this.props.channelID,
        this.props.liveToVODStreamID,
      );
    }
    if (this.props.match.params.channel !== prevProps.match.params.channel) {
      this.props.transitionToTargetChannel(this.props.match.params.channel);
    }
  }

  get player(): JSX.Element {
    return (
      <ChannelVideoPlayer
        channel={this.props.hostedChannel || this.props.match.params.channel}
        sessionID={this.props.sessionID}
        hostChannel={
          this.props.hostedChannel && this.props.match.params.channel
        }
      />
    );
  }

  render(): JSX.Element {
    if (this.props.liveToVODTargetVODid) {
      return <Redirect to={`/videos/${this.props.liveToVODTargetVODid}`} />;
    }

    return (
      <div className="channel-view page">
        <Helmet>
          <title>
            {`${this.props.channelDisplayName ||
              this.props.match.params.channel} Twitch`}
          </title>
        </Helmet>
        {this.player}
        <InfoBox
          channelName={this.props.match.params.channel}
          channelDisplayName={this.props.channelDisplayName}
          logoUrl={this.props.logoUrl}
          game={this.props.game}
          hostedChannel={this.props.hostedChannel}
          hostedChannelDisplayName={this.props.hostedChannelDisplayName}
        />
        <ClientOnly hasLatencyTrackedChildren>
          <ChannelViewerBottomPane
            showChat={this.props.showChat}
            isChatReady={this.props.isChatReady}
            game={this.props.game}
            switchToDesktop={this.props.switchToDesktop}
            chatMessages={this.props.chatMessages}
          />
          <BranchUpsellExperiment
            delaySecondsUntilUpsell={120}
            journey={{
              type: BranchJourneyType.Live,
              channel:
                this.props.channelDisplayName ||
                this.props.match.params.channel,
            }}
          />
          <BranchTimedTrackerExperiment
            delaySecondsUntilTrack={5 * 60}
            event={BranchEvent.FiveMinutePlay}
          />
        </ClientOnly>
      </div>
    );
  }
}

function mapStateToProps(
  state: RootState,
): ChannelViewerStateProps & ErrorStatableOwnProps {
  const {
    currentChannel,
    hostedChannel,
    liveToVODStreamID,
    liveToVODTargetVODid,
  } = state.pages.channelViewer;
  const channel = getChannelDetails(state, currentChannel);
  const hosted = getChannelDetails(state, hostedChannel);
  return {
    liveToVODStreamID,
    liveToVODTargetVODid,
    channelDisplayName: channel && channel.displayName,
    channelID: channel && channel.id,
    logoUrl: channel && channel.logoURL,
    game: (hosted && hosted.game) || (channel && channel.game),
    hostedChannel: hosted && hosted.name,
    hostedChannelDisplayName: hosted && hosted.displayName,
    chatMessages: state.chat.messages,
    showChat: state.pages.channelViewer.showChat,
    sessionID: state.device.sessionID,
    isChatReady: isChatReady(state),
    notFound: statusNotFound(state),
    internalError: statusInternalError(state),
  };
}

function mapDispatchToProps(
  dispatch: Dispatch<RootState>,
): ChannelViewerDispatchProps {
  return bindActionCreators(
    {
      transitionToTargetChannel: channelViewerPageTransition,
      checkLiveToVODStatus: channelViewerCheckLiveToVODStatus,
      switchToDesktop: navigationDeclineMobileWebExperience,
    },
    dispatch,
  );
}

export default connect(mapStateToProps, mapDispatchToProps)(
  ErrorStateWrapper(withLatencyTracker(ChannelViewer)),
) as React.ComponentClass<ChannelViewerOwnProps>;
