import { groupBy, forOwn } from '../../utils/lang';
import SplitIO from '../../../types/splitio';
import { submitterFactory } from './submitter';
import { ImpressionsPayload } from './types';
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
import { EntityType, ISdkFactoryContextSync } from '../../sdkFactory/types';

/**
 * Converts `impressions` data from cache into request payload.
 */
export function fromImpressionsCollector(sendLabels: boolean, entityType: EntityType | undefined, data: SplitIO.ImpressionDTO[]): ImpressionsPayload {
  let groupedByFeature = groupBy(data, 'feature');
  let dto: ImpressionsPayload = [];

  forOwn(groupedByFeature, (value, name) => {
    dto.push({
      f: name, // Definition type
      i: value.map(entry => { // Key Impressions
        return {
          k: entry.keyName, // Key
          t: entry.treatment, // Treatment
          m: entry.time, // Timestamp
          c: entry.changeNumber, // ChangeNumber
          r: sendLabels ? entry.label : undefined, // Rule
          b: entry.bucketingKey, // Bucketing Key
          pt: entry.pt, // Previous time
          properties: entry.properties, // Properties
          et: entityType, // Definition type
        };
      })
    });
  });

  return dto;
}

/**
 * Submitter that periodically posts impressions data
 */
export function impressionsSubmitterFactory(params: ISdkFactoryContextSync) {

  const {
    settings: { log, scheduler: { impressionsRefreshRate }, core: { labelsEnabled } },
    serviceApi: { postTestImpressionsBulk },
    storage: { impressions },
    entityType
  } = params;

  // retry impressions only once.
  const syncTask = submitterFactory(log, postTestImpressionsBulk, impressions, impressionsRefreshRate, fromImpressionsCollector.bind(undefined, labelsEnabled, entityType), 1);

  // register impressions submitter to be executed when impressions cache is full
  impressions.setOnFullQueueCb(() => {
    if (syncTask.isRunning()) {
      log.info(SUBMITTERS_PUSH_FULL_QUEUE, [impressions.name]);
      syncTask.execute();
    }
    // If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
    // Data will be sent when submitter is resumed.
  });

  return syncTask;
}
