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

import { ChannelOfflineToast } from 'mweb/common/components/channelOfflineToast';
import { ChannelDetails } from 'mweb/common/reducers/data/channels';
import { VideoType } from 'mweb/common/reducers/data/baseVideoDetails';
import { ChannelInfoCard } from 'mweb/common/components/channelInfoCard';
import { FeaturedContentCard } from 'mweb/common/components/featuredContentCard';
import { ChannelProfileVideoList } from 'mweb/common/components/channelProfileVideoList';
import {
  statusInternalError,
  statusNotFound,
  RootState,
} from 'mweb/common/reducers/root';
import {
  showChannelOfflineToast,
  showProfileEmptyState,
  hasReceivedVodsAndClipsForChannel,
  getProfilePageContent,
  ChannelProfileContent,
  ChannelProfileContentCounts,
} from 'mweb/common/selectors/pages/channelProfile';
import { getChannelDetails } from 'mweb/common/selectors/data/channels';
import { channelProfilePageTransition } from 'mweb/common/actions/pages/channelProfile';
import { withLatencyTracker } from 'mweb/common/latency/withLatencyTracker';
import {
  ErrorStateWrapper,
  ErrorStatableOwnProps,
} from 'mweb/common/components/errors/errorStateWrapper';
import { ProfileEmptyState } from 'mweb/common/components/profileEmptyState';
import Spinner from 'mweb/common/components/spinner';
import { ClientOnly } from 'mweb/common/containers/clientOnly';
import { BranchUpsellExperiment } from 'mweb/common/components/branchUpsell';
import { BranchJourneyType } from 'branch-io';

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

export interface ChannelProfileStateProps {
  channel: ChannelDetails | undefined;
  hostedChannel: ChannelDetails | undefined;
  content: ChannelProfileContent;
  showChannelOfflineToast: boolean;
  showProfileEmptyState: boolean;
  hasReceivedVodsAndClipsForChannel: boolean;
}

export interface ChannelProfileMatchParams {
  channel: string;
}

export interface ChannelProfileOwnProps
  extends RouteComponentProps<ChannelProfileMatchParams> {}

export interface ChannelProfileDispatchProps {
  transition: (
    channel: string,
    videoCounts: ChannelProfileContentCounts,
  ) => void;
}

export interface ChannelProfileProps
  extends ChannelProfileOwnProps,
    ChannelProfileStateProps,
    ChannelProfileDispatchProps {}

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

  isInteractive(): boolean {
    return (
      !!this.props.channel && !!this.props.hasReceivedVodsAndClipsForChannel
    );
  }

  get bodyContent(): JSX.Element | JSX.Element[] {
    if (!this.props.channel || !this.props.hasReceivedVodsAndClipsForChannel) {
      return (
        <Spinner
          name="cube-grid"
          wrapperClassName="mw-channel-profile__loading-spinner"
        />
      );
    }

    if (this.props.showProfileEmptyState) {
      return <ProfileEmptyState />;
    }

    const body = [];
    if (this.props.content.featuredContent) {
      body.push(
        <FeaturedContentCard
          key="featured"
          content={this.props.content.featuredContent}
          isHosting={!!this.props.hostedChannel}
          hostingChannel={this.props.channel.name}
        />,
      );
    }
    if (this.props.content.archives.length > 0) {
      body.push(
        <ChannelProfileVideoList
          key="archives"
          channel={this.props.channel.displayName}
          videos={this.props.content.archives}
          type={VideoType.Archive}
        />,
      );
    }
    if (this.props.content.recentClips.length > 0) {
      body.push(
        <ChannelProfileVideoList
          key="clips"
          channel={this.props.channel.displayName}
          videos={this.props.content.recentClips}
          type={VideoType.Clip}
        />,
      );
    }
    if (this.props.content.recentHighlights.length > 0) {
      body.push(
        <ChannelProfileVideoList
          key="highlights"
          channel={this.props.channel.displayName}
          videos={this.props.content.recentHighlights}
          type={VideoType.Highlight}
        />,
      );
    }
    if (this.props.content.otherVideos.length > 0) {
      body.push(
        <ChannelProfileVideoList
          key="other-videos"
          channel={this.props.channel.displayName}
          videos={this.props.content.otherVideos}
          type={undefined}
        />,
      );
    }

    return body;
  }

  get channelInfoCard(): JSX.Element {
    const channel = this.props.channel;
    return (
      <ChannelInfoCard
        name={this.props.match.params.channel}
        displayName={channel && channel.displayName}
        bannerImageURL={channel && channel.bannerImageURL}
        description={channel && channel.description}
        followerCount={channel && channel.followerCount}
        lifetimeViewerCount={channel && channel.lifetimeViewerCount}
        logoURL={channel && channel.logoURL}
        onlineStatus={channel && channel.onlineStatus}
        video={this.props.content.infoCardVideo}
      />
    );
  }

  get branchUpsell(): JSX.Element {
    return (
      <ClientOnly>
        <BranchUpsellExperiment
          delaySecondsUntilUpsell={this.props.showChannelOfflineToast ? 30 : 5}
          journey={{
            type: BranchJourneyType.Profile,
            channel: this.props.channel
              ? this.props.channel.displayName
              : this.props.match.params.channel,
          }}
        />
      </ClientOnly>
    );
  }

  render(): JSX.Element {
    return (
      <div>
        {this.props.showChannelOfflineToast && (
          <ChannelOfflineToast
            displayName={
              this.props.channel
                ? this.props.channel.displayName
                : this.props.match.params.channel
            }
          />
        )}
        {this.channelInfoCard}
        {this.bodyContent}
        {this.branchUpsell}
      </div>
    );
  }
  componentDidMount(): void {
    this.props.transition(
      this.props.match.params.channel,
      this.props.content.targetVideoCounts,
    );
  }
}

function mapStateToProps(
  state: RootState,
): ChannelProfileStateProps & ErrorStatableOwnProps {
  const channel = state.pages.channelProfile.currentChannel;
  const channelDetails = getChannelDetails(state, channel);
  const hostedChannelDetails = getChannelDetails(
    state,
    channelDetails ? channelDetails.hostedChannel : undefined,
  );
  return {
    content: getProfilePageContent(state),
    channel: channelDetails,
    hostedChannel: hostedChannelDetails,
    notFound: statusNotFound(state),
    internalError: statusInternalError(state),
    showChannelOfflineToast: showChannelOfflineToast(state),
    showProfileEmptyState: showProfileEmptyState(state),
    hasReceivedVodsAndClipsForChannel: hasReceivedVodsAndClipsForChannel(state),
  };
}

function mapDispatchToProps(
  dispatch: Dispatch<RootState>,
): ChannelProfileDispatchProps {
  return bindActionCreators(
    {
      transition: channelProfilePageTransition,
    },
    dispatch,
  );
}

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