import * as cdk from "@aws-cdk/core";
import * as elasticache from "@aws-cdk/aws-elasticache";
import { AlarmSNSTopics } from "../metrics/alarm-sns-topics";
import { Alarms, InstanceTypeInfo } from "./alarms";
import { EnvName } from "../../env-names";
export { InstanceTypeInfo } from "./alarms";

/**
 * cache.m5.large is the smallest current gen, constant performance cache instance type.
 */
export const cacheM5Large: InstanceTypeInfo = {
  name: "cache.m5.large",
  numCPUs: 2,
  memoryBytes: 6.38 * 1024 * 1024 * 1024
};

export interface RedisStackProps extends cdk.StackProps {
  readonly alarmTwitchSeverity: number;
  readonly cloudwatchAlarmSNSTopics: AlarmSNSTopics;
  readonly clusterDesc: string;
  readonly envName: EnvName;
  readonly nodeType: InstanceTypeInfo;
  readonly numNodesPerShard: number;
  readonly numShards: number;
  readonly securityGroupIDs: string[];
  readonly shardNamePrefix: string;
}

/**
 * RedisStack creates a Redis cluster and Cloudwatch alarms for the cluster.
 */
export class RedisStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props: RedisStackProps) {
    super(scope, id, props);

    const redisCluster = new elasticache.CfnReplicationGroup(
      this,
      "RedisCluster",
      {
        automaticFailoverEnabled: true,
        cacheNodeType: props.nodeType.name,
        cacheParameterGroupName: "default.redis5.0.cluster.on",
        cacheSubnetGroupName: "cache-subnets",
        engine: "redis",
        engineVersion: "5.0.6",
        numNodeGroups: props.numShards,
        replicationGroupId: props.shardNamePrefix,
        replicasPerNodeGroup: props.numNodesPerShard - 1,
        replicationGroupDescription: props.clusterDesc,
        securityGroupIds: props.securityGroupIDs
      }
    );
    redisCluster.cfnOptions.updatePolicy = {
      useOnlineResharding: true
    };

    // Create Cloudwatch alarms for the Redis cluster.
    new Alarms(this, "Alarms", {
      cloudwatchAlarmSNSTopics: props.cloudwatchAlarmSNSTopics,
      clusterName: props.shardNamePrefix,
      envName: props.envName,
      instanceType: cacheM5Large,
      numShards: props.numShards,
      numNodesPerShard: props.numNodesPerShard,
      twitchSeverity: props.alarmTwitchSeverity
    });
  }
}
