import * as cdk from "aws-cdk-lib";
import { SlackChannelConfiguration } from "aws-cdk-lib/aws-chatbot";
import { AnyPrincipal, Effect, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from "aws-cdk-lib/aws-iam";
import { Topic } from "aws-cdk-lib/aws-sns";
import { StringParameter } from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";
import { SLACK_WORKSPACE_ID } from "./const";

export type StageAlertProps = {
  readonly slackChannelId: string;
  readonly slackChannelName: string;
};

interface StackProps extends cdk.StackProps {
  readonly accountAlias: string;
  readonly stageAlertProps: StageAlertProps;
}

export class StageAlertStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);
    const { slackChannelId, slackChannelName } = props.stageAlertProps;

    // Amazon Q Developer in chat applications
    const chatbotRole = new Role(this, "ChatbotRole", {
      roleName: `StageAlertChatbotRole`,
      assumedBy: new ServicePrincipal("chatbot.amazonaws.com"),
      inlinePolicies: {
        ChatbotPolicy: new PolicyDocument({
          statements: [
            new PolicyStatement({
              effect: Effect.ALLOW,
              actions: ["cloudwatch:Describe*", "cloudwatch:Get*", "cloudwatch:List*"],
              resources: ["*"],
            }),
          ],
        }),
      },
    });
    const slackConfig = new SlackChannelConfiguration(this, "SlackChannelConfiguration", {
      slackChannelConfigurationName: slackChannelName,
      role: chatbotRole,
      slackChannelId,
      slackWorkspaceId: SLACK_WORKSPACE_ID,
    });
    new StringParameter(this, "ParamStageAlertSlackConfigArn", {
      parameterName: `/account/stage-alert-slack-config-arn`,
      stringValue: slackConfig.slackChannelConfigurationArn,
    });

    // SNSトピックを作成
    const topicName = `${props.accountAlias}-stage-alert-topic`;
    const stageAlertTopic = new Topic(this, "StageAlertTopic", {
      topicName: topicName,
    });
    stageAlertTopic.addToResourcePolicy(
      new PolicyStatement({
        sid: "SNSPublishingPermissions",
        effect: Effect.ALLOW,
        principals: [new AnyPrincipal()],
        actions: ["sns:Publish"],
        resources: [stageAlertTopic.topicArn],
      }),
    );
    slackConfig.addNotificationTopic(stageAlertTopic);
    new StringParameter(this, "ParamStageAlertTopicArn", {
      parameterName: `/account/stage-alert-topic-arn`,
      stringValue: stageAlertTopic.topicArn,
    });
  }
}
