// reflect-metadata polyfill should be imported once in the entire application because the Reflect object is meant to be a global singleton.
import 'reflect-metadata';

import { Context, DynamoDBStreamEvent } from 'aws-lambda';
import AWS from 'aws-sdk';

import { ApplicationContainer } from '../app/application-container';
import { EventItem } from './publisher/event-publisher.interface';

// cache container instance if we get the same lambda container
let _applicationContainer: ApplicationContainer;

export const handler = async (event: DynamoDBStreamEvent, context: Context): Promise<void> => {
  const kinesis = new AWS.Kinesis();

  if (!_applicationContainer) {
    _applicationContainer = ApplicationContainer.instance();
  }

  _applicationContainer.logger.debug('Dynamo Kinesis Adaptor Event: %o', event);

  // push each dynamo stream EventItem record to a Kinesis Stream Event record
  const records = event.Records.filter(record => record.eventName === 'INSERT' && record.eventSource === 'aws:dynamodb').map(record => {
    const eventItem: EventItem = AWS.DynamoDB.Converter.unmarshall(record.dynamodb.NewImage) as EventItem;

    return {
      Data: JSON.stringify(eventItem.event),
      PartitionKey: record.dynamodb.Keys.id.S,
      SequenceNumberForOrdering: record.dynamodb.Keys.$version.N,
      StreamName: process.env.eventSourceStream
    };
  });

  // push each kinesis record in order
  for (const record of records)  {
    const result = await kinesis.putRecord(record).promise();
    _applicationContainer.logger.debug('Inserted Kinesis record: %o\n\rResult: %o', record, result);
  }
};