import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { Location } from 'history';
import { Redirect } from 'react-router-dom';

import {
  channelViewerPageCaptureLiveToVODParams,
  LiveToVODParams,
} from 'mweb/common/actions/pages/channelViewer';
import {
  trackingCaptureTrackingParams,
  TwitchTrackingParams,
} from 'mweb/common/actions/tracking';
import { RootState } from 'mweb/common/reducers/root';
import getQueryParamsFromHistoryLocation from 'mweb/common/utils/getQueryParamsFromHistoryLocation';

// these params are handled upstream to the client and are removed here for cleanliness
interface SilencedNoopParams {
  'desktop-redirect': string | undefined;
}

export type QueryParamCapturerParams =
  | TwitchTrackingParams
  | LiveToVODParams
  | SilencedNoopParams;

export interface QueryParamCapturerCaptureProps {
  captureTrackingParams: (params: TwitchTrackingParams) => any;
  captureLiveToVODParams: (params: LiveToVODParams) => any;
}

export interface QueryParamCapturerDispatchProps
  extends QueryParamCapturerCaptureProps {}

export interface QueryParamCapturerOwnProps {
  location: Location;
}

export interface QueryParamCapturerProps
  extends QueryParamCapturerDispatchProps,
    QueryParamCapturerOwnProps {}

interface QueryParamCapturerState {
  shouldRedirect: boolean;
}

interface BaseParamsGroupData {
  propsFunc?: keyof QueryParamCapturerCaptureProps;
}

interface TrackingParamsGroupData extends BaseParamsGroupData {
  propsFunc: 'captureTrackingParams';
  payload: TwitchTrackingParams;
}

interface LiveToVODParamsGroupData extends BaseParamsGroupData {
  propsFunc: 'captureLiveToVODParams';
  payload: LiveToVODParams;
}

interface SilencedNoopParamsGroupData extends BaseParamsGroupData {
  payload: SilencedNoopParams;
}

type ParamsGroupData =
  | TrackingParamsGroupData
  | LiveToVODParamsGroupData
  | SilencedNoopParamsGroupData;

const targetParams: ParamsGroupData[] = [
  {
    payload: { tt_content: undefined, tt_medium: undefined },
    propsFunc: 'captureTrackingParams',
  },
  {
    payload: { stream_id: undefined },
    propsFunc: 'captureLiveToVODParams',
  },
  {
    payload: { 'desktop-redirect': undefined },
  },
];

export class QueryParamCapturer extends React.Component<
  QueryParamCapturerProps,
  QueryParamCapturerState
> {
  constructor(props: QueryParamCapturerProps) {
    super(props);
    this.state = { shouldRedirect: false };
  }

  componentWillMount(): void {
    const capturedParams = getQueryParamsFromHistoryLocation(
      this.props.location,
    );
    let shouldRedirect = false;

    targetParams.forEach(({ payload, propsFunc }) => {
      let anyParamMatched = false;
      Object.keys(payload).forEach(param => {
        payload = { ...payload, [param]: capturedParams[param] };
        anyParamMatched =
          anyParamMatched || (payload as any)[param] !== undefined;
      });

      if (anyParamMatched) {
        shouldRedirect = true;
        if (propsFunc) {
          (this.props[propsFunc] as (params: QueryParamCapturerParams) => any)(
            payload,
          );
        }
      }
    });

    if (shouldRedirect) {
      this.setState({ shouldRedirect });
    }
  }

  componentDidMount(): void {
    this.setState({ shouldRedirect: false });
  }

  render(): JSX.Element | null {
    if (this.state.shouldRedirect) {
      const params = getQueryParamsFromHistoryLocation(this.props.location);
      targetParams.forEach(({ payload }) => {
        Object.keys(payload).forEach(param => {
          delete params[param];
        });
      });

      return (
        <Redirect
          to={{
            pathname: this.props.location.pathname,
            search: Object.keys(params)
              .map(k => `${k}=${params[k]}`)
              .join('&'),
          }}
        />
      );
    }

    return null;
  }
}

function mapDispatchToProps(
  dispatch: Dispatch<RootState>,
): QueryParamCapturerDispatchProps {
  return bindActionCreators(
    {
      captureTrackingParams: trackingCaptureTrackingParams,
      captureLiveToVODParams: channelViewerPageCaptureLiveToVODParams,
    },
    dispatch,
  );
}

export default connect(undefined, mapDispatchToProps)(
  QueryParamCapturer,
) as React.ComponentClass<QueryParamCapturerOwnProps>;
