import { CfnOutput } from "@aws-cdk/core";
import * as iam from "@aws-cdk/aws-iam";
import * as cognito from "@aws-cdk/aws-cognito";
import * as sst from "@serverless-stack/resources";

export default class CognitoStack extends sst.Stack {
  constructor(scope, id, props) {
    super(scope, id, props);

    const { bucketArn } = props;

    const stage = this.node.root.stage;
    const service = this.node.root.name;

    const userPool = new cognito.UserPool(this, "userPool", {
      selfSignUpEnabled: true,
      autoVerify: { email: true },
      signInAliases: { email: true }, // Set email as an alias
    });

    const userPoolClient = new cognito.UserPoolClient(this, "userPoolClient", {
      userPool,
      authFlows: { adminUserPassword: false },
      generateSecret: false,
    });

    const identityPool = new cognito.CfnIdentityPool(this, "identityPool", {
      allowUnauthenticatedIdentities: false, // Don't allow unathenticated users
      cognitoIdentityProviders: [
        {
          clientId: userPoolClient.userPoolClientId,
          providerName: userPool.userPoolProviderName,
        },
      ],
    });

    // IAM role used for authenticated users
    const authenticatedRole = new iam.Role(
      this,
      "cognitoDefaultAuthenticatedRole",
      {
        assumedBy: new iam.FederatedPrincipal(
          "cognito-identity.amazonaws.com",
          {
            StringEquals: {
              "cognito-identity.amazonaws.com:aud": identityPool.ref,
            },
            "ForAnyValue:StringLike": {
              "cognito-identity.amazonaws.com:amr": "authenticated",
            },
          },
          "sts:AssumeRoleWithWebIdentity"
        ),
      }
    );
    authenticatedRole.addToPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: [
          "mobileanalytics:PutEvents",
          "cognito-sync:*",
          "cognito-identity:*",
        ],
        resources: ["*"],
      })
    );
    authenticatedRole.addToPolicy(
      new iam.PolicyStatement({
        effect: iam.Effect.ALLOW,
        actions: ["s3:*"],
        resources: [
          bucketArn + "/private/${cognito-identity.amazonaws.com:sub}/*",
        ],
      })
    );

    new cognito.CfnIdentityPoolRoleAttachment(
      this,
      "identityPoolRoleAttachment",
      {
        identityPoolId: identityPool.ref,
        roles: { authenticated: authenticatedRole.roleArn },
      }
    );

    // Export values
    new CfnOutput(this, "userPoolId", {
      value: userPool.userPoolId,
    });
    new CfnOutput(this, "userPoolClientId", {
      value: userPoolClient.userPoolClientId,
    });
    new CfnOutput(this, "identityPoolId", {
      value: identityPool.ref,
    });
    new CfnOutput(this, "authenticatedRoleName", {
      exportName: `ExtCognitoAuthRole-${stage}-${service}`,
      value: authenticatedRole.roleName,
    });
  }
}
