text: from typing import Optional
  from .boto_session import BotoInterface
  from troposphere import (
      Ref as cf_Ref,
      Template as cf_Template,
      Parameter as cf_Parameter,
      Output as cf_Output,
      GetAtt as cf_GetAtt,
      Join as cf_Join,
  )
  from troposphere import (
      apigateway as cf_apigateway,
      codebuild as cf_codebuild,
      ecr as cf_ecr,
      s3 as cf_s3,
      awslambda as cf_awslambda,
  )
  from troposphere.iam import Policy, Role
  from troposphere.constants import NUMBER as cf_NUMBER
  from troposphere.codebuild import (
      Artifacts as cf_Artifcats,
      Environment as cf_Environment,
      Project as cf_Project,
      Source as cf_Source,
  )
  from troposphere.apigateway import (
      ApiStage as cf_ApiStage,
      Deployment as cf_Deployment,
      EndpointConfiguration,
      Integration as cf_Integration,
      IntegrationResponse as cf_IntegrationResponse,
      Method as cf_Method,
      MethodResponse as cf_MethodResponse,
      Resource as cf_Resource,
      RestApi as cf_RestApi,
      Stage as cf_Stage,
  )
  
  from troposphere.awslambda import (
      Code as cf_Code,
      Function as cf_Function,
      Permission as cf_Permission,
      MAXIMUM_MEMORY as cf_MAXIMUM_MEMORY,
      MINIMUM_MEMORY as cf_MINIMUM_MEMORY,
  )
  from troposphere.iam import Policy as cf_Policy, Role as cf_Role
  import logging
  
  logger = logging.getLogger(__name__)
  
  
  class CloudFormation(BotoInterface):
      """
      AWS CloudFormation Template Class
      """
  
      def __init__(self, profile_name: str, *args, **kwargs) -> None:
          super().__init__(profile_name=profile_name)
          self.cloudformation_client = self.boto_client.client("cloudformation")
          self.profile_name = profile_name
          self.cloud_template = cf_Template()
          # self.cloud_template.set_description(description)
          self.ACCOUNT_ID = self.aws_account_id
          # TODO: CHANGE DEFAULT REGION
          self.REGION = "us-east-1"
          self.LAMBDA_FUNCTION_NAME = self.LAMBDA_EXECUTION_ROLE_NAME = self.API_NAME = ""
  
      def to_dict(self) -> dict:
          """
          Method to convert class instance to dictionary
          """
          output_dict = {}
          output_dict["profile_name"] = self.profile_name
          output_dict["cloud_template"] = self.cloud_template.to_dict()
          output_dict["ACCOUNT_ID"] = self.ACCOUNT_ID
          output_dict["REGION"] = self.REGION
          output_dict["LAMBDA_FUNCTION_NAME"] = self.LAMBDA_FUNCTION_NAME
          return output_dict
  
      def __repr__(self) -> str:
          return f"CloudFormation(profile_name={self.profile_name})"
  
      def __str__(self) -> str:
          return f"CloudFormation(profile_name={self.profile_name})"
  
      def create_s3_bucket(self) -> None:
          # s3_bucket = s3.Bucket(title='ProphetoTestBucket20210719', )
          # cloud_template.add_resource(s3_bucket)
          pass
  
      def create_lambda_function(
          self,
          ImageURI: Optional[str] = None,
          CodeBucket: Optional[str] = None,
          CodeKey: Optional[str] = None,
      ) -> None:
          # TODO: FUNCTION AND ROLE NAMES
          self.LAMBDA_FUNCTION_NAME = "ProphetoApiExecuteFunction"
          self.LAMBDA_EXECUTION_ROLE_NAME = "ProphetoLambdaExecutionRole"
  
          MemorySize = self.cloud_template.add_parameter(
              cf_Parameter(
                  "LambdaMemorySize",
                  Type=cf_NUMBER,
                  Description="Amount of memory to allocate to the Lambda Function",
                  Default="128",
                  MinValue=cf_MINIMUM_MEMORY,
                  MaxValue=cf_MAXIMUM_MEMORY,
              )
          )
  
          Timeout = self.cloud_template.add_parameter(
              cf_Parameter(
                  "LambdaTimeout",
                  Type=cf_NUMBER,
                  Description="Timeout in seconds for the Lambda function",
                  Default="600",
              )
          )
  
          LambdaExecutionRole = self.cloud_template.add_resource(
              cf_Role(
                  self.LAMBDA_EXECUTION_ROLE_NAME,
                  Path="/",
                  Policies=[
                      cf_Policy(
                          PolicyName="root",
                          PolicyDocument={
                              "Version": "2012-10-17",
                              "Statement": [
                                  {
                                      "Action": ["logs:*"],
                                      "Resource": "arn:aws:logs:*:*:*",
                                      "Effect": "Allow",
                                  },
                                  {
                                      "Action": ["lambda:*"],
                                      "Resource": "*",
                                      "Effect": "Allow",
                                  },
                              ],
                          },
                      )
                  ],
                  AssumeRolePolicyDocument={
                      "Version": "2012-10-17",
                      "Statement": [
                          {
                              "Action": ["sts:AssumeRole"],
                              "Effect": "Allow",
                              "Principal": {
                                  "Service": [
                                      "lambda.amazonaws.com",
                                      "apigateway.amazonaws.com",
                                  ]
                              },
                          }
                      ],
                  },
              )
          )
          if ImageURI:
              CODE = cf_Code(ImageUri=ImageURI)
              ApiExecuteFunction = self.cloud_template.add_resource(
                  cf_Function(
                      self.LAMBDA_FUNCTION_NAME,
                      Code=CODE,
                      PackageType="Image",
                      Role=cf_GetAtt(self.LAMBDA_EXECUTION_ROLE_NAME, "Arn"),
                      MemorySize=cf_Ref(MemorySize),
                      Timeout=cf_Ref(Timeout),
                  )
              )
          else:
              CODE = cf_Code(S3Bucket=CodeBucket, S3Key=CodeKey,)
              ApiExecuteFunction = self.cloud_template.add_resource(
                  cf_Function(
                      self.LAMBDA_FUNCTION_NAME,
                      Code=CODE,
                      Handler="main.handler",
                      Role=cf_GetAtt(self.LAMBDA_EXECUTION_ROLE_NAME, "Arn"),
                      Runtime="python3.8",
                      MemorySize=cf_Ref(MemorySize),
                      Timeout=cf_Ref(Timeout),
                  )
              )
  
      def create_api_gateway(self) -> object:
          # TODO: PASS IN API NAME
          self.API_NAME = "ProphetoTestApiGateway20210719v7"
          rest_api = self.cloud_template.add_resource(
              cf_RestApi(
                  self.API_NAME,
                  Name=self.API_NAME,
                  EndpointConfiguration={"Types": ["REGIONAL"]},
              )
          )
  
          # Create a resource to map the lambda function to
          # Create a Lambda API method for the Lambda resource
          URI = cf_Join(
              "",
              [
                  f"arn:aws:apigateway:{self.REGION}:lambda:path/2015-03-31/functions/",
                  cf_GetAtt(self.LAMBDA_FUNCTION_NAME, "Arn"),
                  "/invocations",
              ],
          )
          ## TODO: UPDATE INTEGRATION RESPONSE FOR JSON
          INTEGRATION = cf_Integration(
              Credentials=cf_GetAtt(self.LAMBDA_EXECUTION_ROLE_NAME, "Arn"),
              Type="AWS_PROXY",
              IntegrationHttpMethod="POST",
              IntegrationResponses=[cf_IntegrationResponse(StatusCode="200")],
              Uri=URI,
          )
  
          parent_method = self.cloud_template.add_resource(
              cf_Method(
                  "ParentLambdaMethod",
                  DependsOn=self.LAMBDA_FUNCTION_NAME,
                  RestApiId=cf_Ref(rest_api),
                  AuthorizationType="NONE",
                  ResourceId=cf_GetAtt(rest_api, "RootResourceId"),
                  HttpMethod="ANY",
                  Integration=INTEGRATION,
                  MethodResponses=[cf_MethodResponse("CatResponse", StatusCode="200")],
              )
          )
  
          # Create a resource to map the lambda function to
          child_proxy_resource = self.cloud_template.add_resource(
              cf_Resource(
                  "MethodResource",
                  DependsOn="ParentLambdaMethod",
                  RestApiId=cf_Ref(rest_api),
                  PathPart="{proxy+}",
                  ParentId=cf_GetAtt(rest_api, "RootResourceId"),
              )
          )
  
          # Create a Lambda API method for the Lambda resource
          child_method = self.cloud_template.add_resource(
              cf_Method(
                  "ChildLambdaMethod",
                  DependsOn="MethodResource",
                  RestApiId=cf_Ref(rest_api),
                  AuthorizationType="NONE",
                  ResourceId=cf_Ref(child_proxy_resource),
                  HttpMethod="ANY",
                  Integration=INTEGRATION,
                  MethodResponses=[cf_MethodResponse("CatResponse", StatusCode="200")],
              )
          )
          return rest_api
  
      def grant_lambda_permissions(self, rest_api: str) -> None:
          parent_permission = self.cloud_template.add_resource(
              cf_Permission(
                  "ParentMethodPermission",
                  FunctionName=cf_Ref(self.LAMBDA_FUNCTION_NAME),
                  Principal="apigateway.amazonaws.com",
                  Action="lambda:InvokeFunction",
                  SourceArn=cf_Join(
                      "",
                      [
                          f"arn:aws:execute-api:{self.REGION}:{self.ACCOUNT_ID}:",
                          cf_Ref(rest_api),
                          "/*/*/",
                      ],
                  ),
              )
          )
          child_permission = self.cloud_template.add_resource(
              cf_Permission(
                  "ChildMethodPermission",
                  FunctionName=cf_Ref(self.LAMBDA_FUNCTION_NAME),
                  Principal="apigateway.amazonaws.com",
                  Action="lambda:InvokeFunction",
                  SourceArn=cf_Join(
                      "",
                      [
                          f"arn:aws:execute-api:{self.REGION}:{self.ACCOUNT_ID}:",
                          cf_Ref(rest_api),
                          "/*/*/*",
                      ],
                  ),
              )
          )
  
      def create_deployment(self, rest_api: object) -> None:
          # # Create a deployment
          stage_name = "v1"
  
          deployment = self.cloud_template.add_resource(
              cf_Deployment(
                  "%sDeployment" % stage_name,
                  DependsOn="ChildLambdaMethod",
                  RestApiId=cf_Ref(rest_api),
              )
          )
  
          stage = self.cloud_template.add_resource(
              cf_Stage(
                  "%sStage" % stage_name,
                  StageName=stage_name,
                  RestApiId=cf_Ref(rest_api),
                  DeploymentId=cf_Ref(deployment),
              )
          )
  
      def create_ecr(self) -> None:
          # ecr_repo = ecr.Repository(title='ProphetoTestECR20210719')
          # cloud_template.add_resource(ecr_repo)
          pass
  
      def create_codebuild(self) -> None:
          # artifacts = Artifacts(Type="NO_ARTIFACTS")
          # environment = Environment(
          #     ComputeType="BUILD_GENERAL1_SMALL",
          #     Image="aws/codebuild/amazonlinux2-x86_64-standard:3.0",
          #     Type="LINUX_CONTAINER",
          #     EnvironmentVariables=[{"Name": "APP_NAME", "Value": "demo"}],
          # )
  
          # source = Source(
          #     # Location="codebuild-demo-test/0123ab9a371ebf0187b0fe5614fbb72c",
          #     Location="codebuildsample-us-east-{accountid}-input-bucket/app.zip",
          #     Type="S3",
          # )
  
          # project = Project(
          #     "ProphetoDemoProject",
          #     Artifacts=artifacts,
          #     Environment=environment,
          #     Name="DemoProject",
          #     ServiceRole="arn:aws:iam::{accountid}:role/service-role/codebuild-test-project-service-role",
          #     Source=source,
          # )
          # cloud_template.add_resource(project)
          pass
  
      def generate_template(self, image_uri: str) -> str:
          self.create_s3_bucket()
          self.create_ecr()
          self.create_codebuild()
          self.create_lambda_function(ImageURI=image_uri)
          rest_api = self.create_api_gateway()
          self.grant_lambda_permissions(rest_api)
          self.create_deployment(rest_api)
          template_body = self.cloud_template.to_json()
          response = self.cloudformation_client.validate_template(
              TemplateBody=template_body
          )
          return self.cloud_template.to_json()
  