import * as cdk from "aws-cdk-lib";
import { SlackChannelConfiguration } from "aws-cdk-lib/aws-chatbot";
import { AccountPrincipal, 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 ContractEventAlertProps = {
  readonly slackChannelId: string;
  readonly slackChannelName: string;
};

interface StackProps extends cdk.StackProps {
  readonly accountAlias: string;
  readonly accountId: string;
  readonly contractEventAlertProps: ContractEventAlertProps;
}

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

    // Amazon Q Developer in chat applications
    const chatbotRole = new Role(this, "ChatbotRole", {
      roleName: `ContractEventAlertChatbotRole`,
      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, "ParamContractEventAlertSlackConfigArn", {
      parameterName: `/account/contract-event-alert-slack-config-arn`,
      stringValue: slackConfig.slackChannelConfigurationArn,
    });

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