# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0

from aws_cdk import aws_ec2 as ec2, aws_eks as eks, core, aws_emrcontainers as emrc, aws_iam as iam, aws_logs as logs, custom_resources as custom, aws_acmpca as acmpca
from OpenSSL import crypto, SSL
import random

"""
This stack deploys the following:
- EMR Studio Prerequisites
"""
class StudioStack(core.Stack):


    def __init__(self, scope: core.Construct, construct_id: str, executionRoleArn: str, virtualClusterId: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # policy to let Lambda invoke the api
        custom_policy_document = iam.PolicyDocument(statements=[
            iam.PolicyStatement(
                effect=iam.Effect.ALLOW,
                actions=["ec2:CreateSecurityGroup",
                        "ec2:RevokeSecurityGroupEgress",
                        "ec2:CreateSecurityGroup",
                        "ec2:DeleteSecurityGroup",
                        "ec2:AuthorizeSecurityGroupEgress",
                        "ec2:AuthorizeSecurityGroupIngress",
                        "ec2:RevokeSecurityGroupIngress",
                        "ec2:DeleteSecurityGroup"
                        ],
                resources=["*"]
            )
        ])
        managed_policy = iam.ManagedPolicy(self, "EMR_on_EKS_security_group",
            document=custom_policy_document
        )

        self.role = iam.Role(
                scope=self,
                id=f'{construct_id}-LambdaRole',
                assumed_by=iam.ServicePrincipal('lambda.amazonaws.com'),
                managed_policies=[
                    iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole"),
                    managed_policy
                ]
            )

        # cert for endpoint
        crt, pkey = self.cert_gen(serialNumber=random.randint(1000,10000))
        mycert = custom.AwsCustomResource(self, "CreateCert",
            on_update={
                "service": "ACM",
                "action": "importCertificate",
                "parameters": {
                    "Certificate": crt.decode("utf-8"),
                    "PrivateKey": pkey.decode("utf-8")
                },
                "physical_resource_id": custom.PhysicalResourceId.from_response("CertificateArn")
            },
            policy=custom.AwsCustomResourcePolicy.from_sdk_calls(resources=custom.AwsCustomResourcePolicy.ANY_RESOURCE),
            role=self.role,
            function_name="CreateCertFn"
        )

        # Set up managed endpoint for Studio
        endpoint = custom.AwsCustomResource(self, "CreateEndpoint",
            on_create={
                "service": "EMRcontainers",
                "action": "createManagedEndpoint",
                "parameters": {
                    "certificateArn": mycert.get_response_field("CertificateArn"),
                    "executionRoleArn": executionRoleArn,
                    "name": "emr-endpoint-eks-spark",
                    "releaseLabel": "emr-6.2.0-latest",
                    "type": "JUPYTER_ENTERPRISE_GATEWAY",
                    "virtualClusterId": virtualClusterId,
                },
                "physical_resource_id": custom.PhysicalResourceId.from_response("arn")},
            policy=custom.AwsCustomResourcePolicy.from_sdk_calls(resources=custom.AwsCustomResourcePolicy.ANY_RESOURCE),
            role=self.role,
            function_name="CreateEpFn"
        )
        endpoint.node.add_dependency(mycert)


    def cert_gen(self,
        emailAddress="emailAddress",
        commonName="emroneks.com",
        countryName="NT",
        localityName="localityName",
        stateOrProvinceName="stateOrProvinceName",
        organizationName="organizationName",
        organizationUnitName="organizationUnitName",
        serialNumber=1234,
        validityStartInSeconds=0,
        validityEndInSeconds=10*365*24*60*60,
        KEY_FILE = "private.key",
        CERT_FILE="selfsigned.crt"):
        #can look at generated file using openssl:
        #openssl x509 -inform pem -in selfsigned.crt -noout -text
        # create a key pair
        k = crypto.PKey()
        k.generate_key(crypto.TYPE_RSA, 2048)
        # create a self-signed cert
        cert = crypto.X509()
        cert.get_subject().C = countryName
        cert.get_subject().ST = stateOrProvinceName
        cert.get_subject().L = localityName
        cert.get_subject().O = organizationName
        cert.get_subject().OU = organizationUnitName
        cert.get_subject().CN = commonName
        cert.get_subject().emailAddress = emailAddress
        cert.set_serial_number(serialNumber)
        cert.gmtime_adj_notBefore(0)
        cert.gmtime_adj_notAfter(validityEndInSeconds)
        cert.set_issuer(cert.get_subject())
        cert.set_pubkey(k)
        cert.sign(k, 'sha512')
        return (crypto.dump_certificate(crypto.FILETYPE_PEM, cert), crypto.dump_privatekey(crypto.FILETYPE_PEM, k))
