import * as cdk from "@aws-cdk/core";
import * as sns from "@aws-cdk/aws-sns";
import { EnvName } from "../../env-names";
import * as subs from "@aws-cdk/aws-sns-subscriptions";

/**
 * Host Production PagerDuty service (https://twitchoncall.pagerduty.com/services/P0PQE2A)
 */
const hostCriticalPagerDutyURL =
  "https://events.pagerduty.com/integration/334204ab7ebb4bbc8504d425af585777/enqueue";

/**
 * Host Production Non-Critical PagerDuty service (https://twitchoncall.pagerduty.com/services/PKHKSCD)
 */
const hostNonCriticalPagerDutyURL =
  "https://events.pagerduty.com/integration/ffcbb18636d041ea8248623297729dff/enqueue";

export interface AlarmSNSTopicsProps {
  readonly envName: EnvName;
}

/**
 * AlarmSNSTopics creates SNS topics that public Cloudwatch alarms to pagers.
 */
export class AlarmSNSTopics extends cdk.Construct {
  /**
   * SNS topic for sev 1 - 2 Cloudwatch alarms.
   * We publish to this topic if the issue is critical enough that an on-call should be woken up.
   * Only exists in Production.
   */
  critical?: sns.ITopic;

  /**
   * SNS topic for sev 2.5 - 5 Cloudwatch alarms.
   * We publish to this topic if the on-call should be paged, but only during business hours.
   * Only exists in Production.
   */
  nonCritical?: sns.ITopic;

  /**
   *  SNS topic for low severity alarms. This topic is not connected to PagerDuty; it sends
   * an email to a Developer.
   */
  debug: sns.ITopic;

  constructor(scope: cdk.Construct, id: string, props: AlarmSNSTopicsProps) {
    super(scope, id);

    if (props.envName == EnvName.Production) {
      this.addProductionOnlyTopics();
    }

    this.debug = new sns.Topic(this, "DebugTopic", {
      displayName: `Debug ${props.envName} alerts`,
      topicName: `${props.envName}-debug-alerts`
    });
    this.debug.addSubscription(new subs.EmailSubscription("jlym@twitch.tv"));
  }

  getCriticalTopic(): sns.ITopic {
    if (!this.critical) {
      throw "critical topic is undefined. (it is only defined for production.)"
    }
    return this.critical;
  }

  getNonCriticalTopic(): sns.ITopic {
    if (!this.nonCritical) {
      throw "non-critical topic is undefined. (it is only defined for production.)"
    }
    return this.nonCritical;
  }

  /**
   * Returns the SNS topic that should be used for alerts for the given severity,
   * or null if this environment does not have a topic for that severity.
   */
  getTopicForSeverity(twitchSeverity: number): sns.ITopic | null {
    if (twitchSeverity <= 2) {
      return this.critical || null;
    }
    return this.nonCritical || null;
  }

  private addProductionOnlyTopics() {
    this.critical = new sns.Topic(this, "CriticalTopic", {
      displayName: "Critical production alerts (Sev 1 - 2)",
      topicName: "production-critical-alerts"
    });
    this.critical.addSubscription(
      new subs.UrlSubscription(hostCriticalPagerDutyURL)
    );

    this.nonCritical = new sns.Topic(this, "NonCriticalTopic", {
      displayName: "Non-Critical production alerts (Sev 2.5 - 5)",
      topicName: "production-non-critical-alerts"
    });
    this.nonCritical.addSubscription(
      new subs.UrlSubscription(hostNonCriticalPagerDutyURL)
    );
  }
}
