import * as cdk from "aws-cdk-lib";
import * as cloudwatch from "aws-cdk-lib/aws-cloudwatch";
import * as cloudwatchactions from "aws-cdk-lib/aws-cloudwatch-actions";
import * as logs from "aws-cdk-lib/aws-logs";
import * as sns from "aws-cdk-lib/aws-sns";
import * as ssm from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";

interface ApiMonitoringProps {
  stage: string;
  apiName: string;
  accessLogGroup: logs.ILogGroup;
}

export class ApiMonitoring extends Construct {
  readonly stageAlertTopicArnParameterName = "/account/stage-alert-topic-arn";

  constructor(scope: Construct, id: string, props: ApiMonitoringProps) {
    super(scope, id);
    const { stage, apiName, accessLogGroup } = props;
    // 500番台のエラーを監視するためのフィルターパターン
    const api5XXErrorFilter = new logs.MetricFilter(this, "Api5XXErrorFilter", {
      logGroup: accessLogGroup,
      metricNamespace: `Custom/${stage}/Api/${apiName}`,
      metricName: "5XXError",
      filterPattern: logs.FilterPattern.stringValue("$.status", "=", "5*"),
      metricValue: "1",
    });

    // CloudWatch Alarms
    const api5XXErrorAlarm = new cloudwatch.Alarm(this, "Api5XXErrorAlarm", {
      alarmName: `${stage}-${apiName}-5xx`,
      metric: api5XXErrorFilter.metric({
        period: cdk.Duration.minutes(1),
        statistic: "Sum",
      }),
      evaluationPeriods: 1,
      threshold: 0,
      comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_THRESHOLD,
      treatMissingData: cloudwatch.TreatMissingData.NOT_BREACHING,
    });
    const stageAlertTopicArn = ssm.StringParameter.valueForStringParameter(this, this.stageAlertTopicArnParameterName);
    const stageAlertTopic = sns.Topic.fromTopicArn(this, "StageAlertTopic", stageAlertTopicArn);
    api5XXErrorAlarm.addAlarmAction(new cloudwatchactions.SnsAction(stageAlertTopic));
  }
}
