import * as cdk from "aws-cdk-lib";
import { CfnSlackChannelConfiguration } from "aws-cdk-lib/aws-chatbot";
import { Effect, IRole, PolicyDocument, PolicyStatement, Role, ServicePrincipal } from "aws-cdk-lib/aws-iam";
import { Construct } from "constructs";
import { SLACK_WORKSPACE_ID } from "./const";
import { HealthAlertStack, HealthAlertStackProps } from "./health-alert-stack";
import { generateTemplateBody } from "./util";

export type HealthAlertProps = {
  readonly regions: string[];
  readonly slackChannelId: string;
  readonly slackChannelName: string;
};

interface StackSetProps extends cdk.StackProps {
  readonly accountAlias: string;
  readonly administrationRole: IRole;
  readonly executionRole: IRole;
  readonly healthAlertProps: HealthAlertProps;
}

export class HealthAlertStackSet extends cdk.Stack {
  constructor(scope: Construct, id: string, props: StackSetProps) {
    super(scope, id, props);

    const { accountId } = new cdk.ScopedAws(this);
    const { accountAlias, administrationRole, executionRole, healthAlertProps } = props;

    const { regions, slackChannelId, slackChannelName } = healthAlertProps;

    const topicName = `${accountAlias}-health-alert-topic`;

    const templateBody = generateTemplateBody<HealthAlertStackProps>(HealthAlertStack, {
      topicName,
    });
    const stackSet = new cdk.CfnStackSet(this, "StackSet", {
      stackSetName: `health-alert-stacks`,
      administrationRoleArn: administrationRole.roleArn,
      executionRoleName: executionRole.roleName,
      permissionModel: "SELF_MANAGED",
      capabilities: ["CAPABILITY_NAMED_IAM"],
      operationPreferences: {
        regionConcurrencyType: "PARALLEL",
      },
      stackInstancesGroup: [
        {
          regions: regions,
          deploymentTargets: {
            accounts: [accountId],
          },
        },
      ],
      templateBody,
    });

    // AWS Chatbot
    const chatbotRole = new Role(this, "ChatbotRole", {
      roleName: `HealthAlertChatbotRole`,
      assumedBy: new ServicePrincipal("chatbot.amazonaws.com"),
      inlinePolicies: {
        ChatbotPolicy: new PolicyDocument({
          statements: [
            new PolicyStatement({
              effect: Effect.ALLOW,
              actions: ["cloudwatch:Describe*", "cloudwatch:Get*", "cloudwatch:List*", "support:*"],
              resources: ["*"],
            }),
          ],
        }),
      },
    });
    const slackChannel = new CfnSlackChannelConfiguration(this, "SlackChannelConfiguration", {
      configurationName: slackChannelName,
      iamRoleArn: chatbotRole.roleArn,
      slackChannelId,
      slackWorkspaceId: SLACK_WORKSPACE_ID,
      snsTopicArns: regions.map((region) => {
        return `arn:aws:sns:${region}:${accountId}:${topicName}`;
      }),
    });
    slackChannel.addDependency(stackSet); //wait for creating Topics
  }
}
