import * as React from 'react';
import { TrackingContext } from 'mweb/common/tracking/trackingProvider';
import {
  ContextTypes,
  contextTypeValidator,
} from 'mweb/common/utils/contextTypeValidator';
import { getComponentName } from 'mweb/common/utils/getComponentName';

type InteractionMediumContext = Pick<TrackingContext, 'interactionMedium'>;

interface InteractionMediumProps {
  medium: string | (() => string);
}

export class InteractionMedium extends React.Component<
  InteractionMediumProps,
  {}
> {
  static contextTypes: ContextTypes<InteractionMediumContext> = {
    interactionMedium: contextTypeValidator,
  };

  static childContextTypes: ContextTypes<InteractionMediumContext> = {
    interactionMedium: contextTypeValidator,
  };

  context: InteractionMediumContext;

  getChildContext = (): InteractionMediumContext => {
    const medium =
      typeof this.props.medium === 'function'
        ? this.props.medium()
        : this.props.medium;
    return {
      interactionMedium: this.context.interactionMedium
        ? `${this.context.interactionMedium}.${medium}`
        : medium,
    };
  };

  render(): JSX.Element {
    return React.Children.only(this.props.children);
  }
}

export function extendInteractionMedium<P>(
  WrappedComponent: React.ComponentType<P>,
  interactionMedium: string | ((props: P) => string),
): React.ComponentType<P> {
  return class InteractionMediumWrapper extends React.Component<P, {}> {
    static displayName: string = `InteractionMedium(${getComponentName(
      WrappedComponent,
    )})`;

    get medium(): string {
      return typeof interactionMedium === 'function'
        ? interactionMedium(this.props)
        : interactionMedium;
    }

    render(): JSX.Element {
      return (
        <InteractionMedium medium={this.medium}>
          <WrappedComponent {...this.props} />
        </InteractionMedium>
      );
    }
  };
}
