import { fetchData } from 'mweb/common/fetch/fetchData';
import {
  ExperimentMetadata,
  ExperimentUUIDs,
} from 'mweb/common/actions/experiments';
import { memoize } from 'mweb/common/utils/memoize';
import { logger } from 'tachyon-logger';
import { Enum } from 'mweb/common/utils/enum';

export const EXPERIMENTS_JSON_URL = 'https://www.twitch.tv/experiments.json';

/**
 * A value grouped with the percentage detailing how often it should be applied.
 */
interface MinexperimentGroup {
  readonly weight: number;
  readonly value: string;
}

/**
 * An enumeration describing the type of experiment in Minexperiment.
 */
export enum MinexperimentType {
  DeviceId = 1,
  UserId,
  ChannelId,
}

/**
 * An experiment currently defined in Minexperiment.
 */
interface Minexperiment {
  readonly uuid: string;
  readonly name: string;
  readonly v: number; // version of experiments.json experiment was updated last
  readonly t: MinexperimentType;
  readonly groups: MinexperimentGroup[];
}

/**
 * A mapping of experiments in Minexperiment keyed on the experiment UUID.
 */
export interface MinexperimentResponse {
  [experimentUUID: string]: Minexperiment;
}

/**
 * Retrieves all metadata from Minexperiment for mobile-web experiments.
 */
export async function fetchExperimentsInMinexperiment(): Promise<
  ExperimentMetadata[]
> {
  let allExperiments: MinexperimentResponse;
  try {
    allExperiments = await fetchData<MinexperimentResponse>(
      EXPERIMENTS_JSON_URL,
    );
  } catch {
    logger.warn(`Unable to fetch ${EXPERIMENTS_JSON_URL}`);
    return [];
  }
  const mobileWebUUIDs = Enum.values(ExperimentUUIDs).map(uuid =>
    uuid.toLowerCase(),
  );

  const isUnique = (uuid: string, index: number, arr: string[]) =>
    arr.indexOf(uuid) === index;

  return Object.keys(allExperiments)
    .filter(uuid => mobileWebUUIDs.includes(uuid.toLowerCase()))
    .filter(isUnique)
    .map(
      uuid =>
        ({
          name: allExperiments[uuid].name,
          groups: allExperiments[uuid].groups,
          uuid,
        } as ExperimentMetadata),
    );
}

/**
 * A memoized version of fetchExperimentsInMinexperiment.
 *
 * This is the primary means of retrieving experiment metadata from
 * minexperiment.
 */
export const fetchExperimentMetadata = memoize(fetchExperimentsInMinexperiment);
