import * as React from 'react';
import {
  Route,
  RouteComponentProps,
  Switch,
  withRouter,
} from 'react-router-dom';

import { NotFound } from 'mweb/common/components/errors/notFound';
import {
  ChannelDirectory,
  ChannelDirectoryMatchParams,
} from 'mweb/common/containers/channelDirectory';
import ChannelProfile from 'mweb/common/containers/channelProfile';
import ChannelViewer from 'mweb/common/containers/channelViewer';
import { ClientOnly } from 'mweb/common/containers/clientOnly';
import GameDirectory from 'mweb/common/containers/gameDirectory';
import HeadContainer from 'mweb/common/containers/head';
import QueryParamCapturer from 'mweb/common/containers/queryParamCapturer';
import TopNav from 'mweb/common/containers/topNav';
import Upsell from 'mweb/common/containers/upsell';
import VODViewer from 'mweb/common/containers/vodViewer';
import EventDetails from 'mweb/common/containers/eventDetails';
import { withRouterLatencyTracker } from 'mweb/common/latency/withRouterLatencyTracker';
import { Location } from 'mweb/common/reducers/app';
import { ROUTES } from 'mweb/common/routes';
import { extendInteractionMedium } from 'mweb/common/tracking/extendInteractionMedium';

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

function renderChannelDirectory(
  props: RouteComponentProps<ChannelDirectoryMatchParams>,
): JSX.Element {
  props.match.params.gameAlias =
    props.match.params.gameAlias &&
    decodeURIComponent(props.match.params.gameAlias);
  return <ChannelDirectory {...props} />;
}

type RouteComponentPropsWithChannel = RouteComponentProps<{ channel: string }>;

function normalizeChannelNameAndRender<
  P extends RouteComponentPropsWithChannel
>(Component: React.ComponentClass): (props: P) => JSX.Element {
  return function(props: P): JSX.Element {
    props.match.params.channel = props.match.params.channel.toLowerCase();
    return <Component {...props} />;
  };
}

export interface RouterProps extends RouteComponentProps<any> {}

class Router extends React.Component<RouterProps, {}> {
  static displayName: string = 'Router';

  routes: JSX.Element[] = ROUTES.map(({ route, location }) => {
    const component = this.locationToComponent(location);
    return (
      <Route
        exact
        path={route}
        component={component && extendInteractionMedium(component, location)}
        key={route}
      />
    );
  }).concat(
    <Route
      key="not-found"
      component={extendInteractionMedium(NotFound, Location.Unknown)}
    />,
  );

  locationToComponent(
    location: Location,
  ): React.ComponentType<{} | RouteComponentProps<any>> | undefined {
    switch (location) {
      case Location.Channel:
        return normalizeChannelNameAndRender(ChannelViewer);
      case Location.ChannelProfile:
        return normalizeChannelNameAndRender(ChannelProfile);
      case Location.VOD:
        return VODViewer;
      case Location.Upsell:
        return Upsell;
      case Location.DirectoryMainGame:
        return GameDirectory;
      case Location.DirectoryGame:
        return renderChannelDirectory;
      case Location.EventDetails:
        return EventDetails;
      default:
        return undefined;
    }
  }

  isInteractive(): boolean {
    return true;
  }

  componentDidUpdate(prevProps: RouteComponentProps<any>): void {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0);
    }
  }

  render(): JSX.Element {
    return (
      <div>
        <ClientOnly>
          <QueryParamCapturer location={this.props.location} />
        </ClientOnly>
        <HeadContainer path={this.props.location.pathname} />
        <TopNav routerLocation={this.props.location} />
        <Switch>{this.routes}</Switch>
      </div>
    );
  }
}

export default withRouter<{}>(withRouterLatencyTracker(Router));
