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

import {
  Layout,
  StyledLayout,
  Text,
  TextType,
  TextTransform,
  Color,
  Grid,
  Column,
  GridGutterSize,
  Display,
  FlexDirection,
  JustifyContent,
} from 'twitch-core-ui';

import {
  isSupportedMobileOS,
  getCurrentEventForEventDetails,
  RootState,
  getVODDetails,
  statusNotFound,
} from 'mweb/common/reducers/root';
import { getChannelDetails } from 'mweb/common/selectors/data/channels';
import { getGameDetails } from 'mweb/common/selectors/data/games';
import { EventInfo } from 'mweb/common/components/eventInfo';
import {
  eventDetailsPageTransition,
  eventDetailsPageShareEvent,
  eventDetailsPageRequestNotification,
} from 'mweb/common/actions/pages/eventDetails';
import {
  ErrorStatableOwnProps,
  ErrorStateWrapper,
} from 'mweb/common/components/errors/errorStateWrapper';
import { withLatencyTracker } from 'mweb/common/latency/withLatencyTracker';
import { isPremiereEvent } from 'mweb/common/utils/premiereUtils';
import { PremiereStatus } from 'mweb/common/reducers/data/events';
import { EventBanner } from 'mweb/common/components/eventBanner';
import {
  EventActions,
  EventActionsDispatchProps,
} from 'mweb/common/components/eventActions';
import EventPanels from 'mweb/common/components/eventPanels';
import { Location } from 'mweb/common/reducers/app';
import { EventModel } from 'mweb/common/reducers/data/events';
import { VODDetails } from 'mweb/common/reducers/data/vods';
import { GameDetails } from 'mweb/common/reducers/data/games';
import { ChannelDetails } from 'mweb/common/reducers/data/channels';
import Spinner from 'mweb/common/components/spinner';

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

export interface EventDetailsStateProps {
  event: EventModel | undefined;
  video: VODDetails | undefined;
  game: GameDetails | undefined;
  channel: ChannelDetails | undefined;
  premiereStatus: PremiereStatus | undefined;
  isMobileOS: boolean;
  appLocation: Location;
}

export interface EventDetailsDispatchProps extends EventActionsDispatchProps {
  transitionToEvent: (eventID: string) => void;
}

export interface EventDetailsMatchParams {
  eventID: string;
}

export interface EventDetailsOwnProps
  extends RouteComponentProps<EventDetailsMatchParams> {}

export interface EventDetailsProps
  extends EventDetailsStateProps,
    EventDetailsDispatchProps,
    EventDetailsOwnProps {}

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

  isInteractive(): boolean {
    return !!this.props.event && !!this.props.event.title;
  }

  componentDidMount(): void {
    this.props.transitionToEvent(this.props.match.params.eventID);
  }

  getEventInfoAndControls(event: EventModel): JSX.Element {
    const startTime = new Date(event.startTime);
    const endTime = new Date(event.endTime);

    return (
      <Layout
        display={Display.Flex}
        flexDirection={FlexDirection.Column}
        justifyContent={JustifyContent.Center}
        padding={{ x: 2, top: 1 }}
        breakpointSmall={{
          padding: { x: 1, top: 0 },
        }}
        fullHeight
      >
        <EventInfo
          startTime={startTime}
          endTime={endTime}
          title={event.title}
          premiereStatus={this.props.premiereStatus}
        />
        <EventActions
          startTime={startTime}
          endTime={endTime}
          title={event.title}
          description={event.description}
          isMobileOS={this.props.isMobileOS}
          appLocation={this.props.appLocation}
          handleNotificationRequest={this.props.handleNotificationRequest}
          handleShare={this.props.handleShare}
          premiereStatus={this.props.premiereStatus}
          channelName={event.channel}
        />
      </Layout>
    );
  }

  getEventBanner(event: EventModel): JSX.Element {
    return (
      <Layout breakpointExtraSmall={{ margin: { x: 2 } }}>
        <EventBanner
          coverImageTemplateURL={event.coverImageTemplateURL}
          startTime={new Date(event.startTime)}
        />
      </Layout>
    );
  }

  get eventPanels(): JSX.Element | undefined {
    if (!this.props.channel) {
      return undefined;
    }
    return (
      <Layout margin={{ x: 1, y: 1 }}>
        <EventPanels
          logoURL={this.props.channel.logoURL}
          channelDisplayName={this.props.channel.displayName}
          game={this.props.game}
          channelName={this.props.channel.name}
          video={this.props.video}
        />
      </Layout>
    );
  }

  getEventDescription(event: EventModel): JSX.Element | undefined {
    return (
      <Layout padding={{ x: 2, bottom: 1 }}>
        <Text
          type={TextType.H5}
          color={Color.Alt2}
          transform={TextTransform.Uppercase}
        >
          <FormattedMessage
            id="event--description"
            defaultMessage="Description"
          />
        </Text>
        <Text className="event-description" type={TextType.P}>
          {event.description}
        </Text>
      </Layout>
    );
  }

  get body(): JSX.Element {
    if (!this.props.event) {
      return (
        <Spinner
          name="cube-grid"
          wrapperClassName="event-page-wrapper__loading-spinner"
        />
      );
    }

    return (
      <StyledLayout
        className="event-page"
        breakpointExtraSmall={{
          padding: { x: 5 },
        }}
        breakpointSmall={{
          padding: { x: 5, top: 1 },
        }}
      >
        <Grid gutterSize={GridGutterSize.None}>
          <Column cols={{ default: 12, sm: 6 }}>
            {this.getEventBanner(this.props.event)}
          </Column>
          <Column cols={{ default: 12, sm: 6 }}>
            {this.getEventInfoAndControls(this.props.event)}
          </Column>
        </Grid>
        {this.eventPanels}
        {this.getEventDescription(this.props.event)}
      </StyledLayout>
    );
  }

  render(): JSX.Element {
    const title = this.props.event
      ? `${this.props.event.title} - Twitch`
      : 'Twitch';
    return (
      <StyledLayout className="event-page-wrapper">
        <Helmet>
          <title>{title}</title>
        </Helmet>
        {this.body}
      </StyledLayout>
    );
  }
}

function mapStateToProps(
  state: RootState,
): EventDetailsStateProps & ErrorStatableOwnProps {
  const event = getCurrentEventForEventDetails(state);
  const channel = event && getChannelDetails(state, event.channel);
  const game =
    event && (event.game ? getGameDetails(state, event.game) : undefined);

  let video;
  let premiereStatus;
  if (event && isPremiereEvent(event)) {
    premiereStatus = event.premiere.status;
    if (event.premiere.vodID) {
      video = getVODDetails(state, event.premiere.vodID);
    }
  }

  return {
    isMobileOS: isSupportedMobileOS(state),
    appLocation: state.app.location,
    event,
    channel,
    game,
    notFound: statusNotFound(state),
    premiereStatus,
    video,
  };
}

function mapDispatchToProps(
  dispatch: Dispatch<RootState>,
): EventDetailsDispatchProps {
  return bindActionCreators(
    {
      transitionToEvent: eventDetailsPageTransition,
      handleShare: eventDetailsPageShareEvent,
      handleNotificationRequest: eventDetailsPageRequestNotification,
    },
    dispatch,
  );
}

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