import json

import boto3
import pytest

from moto import mock_aws

template = """{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "The AWS CloudFormation template for this Serverless application",
  "Resources": {
    "ServerlessDeploymentBucket": {
      "Type": "AWS::S3::Bucket"
    },
    "HelloLogGroup": {
      "Type": "AWS::Logs::LogGroup",
      "Properties": {
        "LogGroupName": "/aws/lambda/timeseries-service-dev-hello"
      }
    },
    "IamRoleLambdaExecution": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "lambda.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Policies": [
          {
            "PolicyName": {
              "Fn::Join": [
                "-",
                [
                  "dev",
                  "timeseries-service",
                  "lambda"
                ]
              ]
            },
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "logs:CreateLogStream"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/timeseries-service-dev-hello:*"
                    }
                  ]
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "logs:PutLogEvents"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/timeseries-service-dev-hello:*:*"
                    }
                  ]
                }
              ]
            }
          }
        ],
        "Path": "/",
        "RoleName": {
          "Fn::Join": [
            "-",
            [
              "timeseries-service",
              "dev",
              "us-east-1",
              "lambdaRole"
            ]
          ]
        }
      }
    },
    "HelloLambdaFunction": {
      "Type": "AWS::Lambda::Function",
      "Properties": {
        "Code": {
          "S3Bucket": {
            "Ref": "ServerlessDeploymentBucket"
          },
          "S3Key": "serverless/timeseries-service/dev/1542744572309-2018-11-20T20:09:32.309Z/timeseries-service.zip"
        },
        "FunctionName": "timeseries-service-dev-hello",
        "Handler": "handler.hello",
        "MemorySize": 1024,
        "Role": {
          "Fn::GetAtt": [
            "IamRoleLambdaExecution",
            "Arn"
          ]
        },
        "Runtime": "python3.11",
        "Timeout": 6
      },
      "DependsOn": [
        "HelloLogGroup",
        "IamRoleLambdaExecution"
      ]
    },
    "HelloLambdaVersionU88Ag36tX5K6Yuze3R8jedH2g7q2TTGuafWQxEnUmo": {
      "Type": "AWS::Lambda::Version",
      "DeletionPolicy": "Retain",
      "Properties": {
        "FunctionName": {
          "Ref": "HelloLambdaFunction"
        },
        "CodeSha256": "+pq+8RveA979z1DNF8UKnFGZfgE07blNyJGust5VJnU="
      }
    },
    "ApiGatewayRestApi": {
      "Type": "AWS::ApiGateway::RestApi",
      "Properties": {
        "Name": "dev-timeseries-service",
        "EndpointConfiguration": {
          "Types": [
            "EDGE"
          ]
        }
      }
    },
    "ApiGatewayResourceHello": {
      "Type": "AWS::ApiGateway::Resource",
      "Properties": {
        "ParentId": {
          "Fn::GetAtt": [
            "ApiGatewayRestApi",
            "RootResourceId"
          ]
        },
        "PathPart": "hello",
        "RestApiId": {
          "Ref": "ApiGatewayRestApi"
        }
      }
    },
    "ApiGatewayMethodHelloGet": {
      "Type": "AWS::ApiGateway::Method",
      "Properties": {
        "HttpMethod": "GET",
        "RequestParameters": {},
        "ResourceId": {
          "Ref": "ApiGatewayResourceHello"
        },
        "RestApiId": {
          "Ref": "ApiGatewayRestApi"
        },
        "ApiKeyRequired": false,
        "AuthorizationType": "NONE",
        "Integration": {
          "IntegrationHttpMethod": "POST",
          "Type": "AWS_PROXY",
          "Uri": {
            "Fn::Join": [
              "",
              [
                "arn:",
                {
                  "Ref": "AWS::Partition"
                },
                ":apigateway:",
                {
                  "Ref": "AWS::Region"
                },
                ":lambda:path/2015-03-31/functions/",
                {
                  "Fn::GetAtt": [
                    "HelloLambdaFunction",
                    "Arn"
                  ]
                },
                "/invocations"
              ]
            ]
          }
        },
        "MethodResponses": []
      }
    },
    "ApiGatewayDeployment1542744572805": {
      "Type": "AWS::ApiGateway::Deployment",
      "Properties": {
        "RestApiId": {
          "Ref": "ApiGatewayRestApi"
        },
        "StageName": "dev"
      },
      "DependsOn": [
        "ApiGatewayMethodHelloGet"
      ]
    },
    "HelloLambdaPermissionApiGateway": {
      "Type": "AWS::Lambda::Permission",
      "Properties": {
        "FunctionName": {
          "Fn::GetAtt": [
            "HelloLambdaFunction",
            "Arn"
          ]
        },
        "Action": "lambda:InvokeFunction",
        "Principal": {
          "Fn::Join": [
            "",
            [
              "apigateway.",
              {
                "Ref": "AWS::URLSuffix"
              }
            ]
          ]
        },
        "SourceArn": {
          "Fn::Join": [
            "",
            [
              "arn:",
              {
                "Ref": "AWS::Partition"
              },
              ":execute-api:",
              {
                "Ref": "AWS::Region"
              },
              ":",
              {
                "Ref": "AWS::AccountId"
              },
              ":",
              {
                "Ref": "ApiGatewayRestApi"
              },
              "/*/*"
            ]
          ]
        }
      }
    }
  },
  "Outputs": {
    "ServerlessDeploymentBucketName": {
      "Value": {
        "Ref": "ServerlessDeploymentBucket"
      }
    },
    "HelloLambdaFunctionQualifiedArn": {
      "Description": "Current Lambda function version",
      "Value": {
        "Ref": "HelloLambdaVersionU88Ag36tX5K6Yuze3R8jedH2g7q2TTGuafWQxEnUmo"
      }
    },
    "ServiceEndpoint": {
      "Description": "URL of the service endpoint",
      "Value": {
        "Fn::Join": [
          "",
          [
            "https://",
            {
              "Ref": "ApiGatewayRestApi"
            },
            ".execute-api.us-east-1.",
            {
              "Ref": "AWS::URLSuffix"
            },
            "/dev"
          ]
        ]
      }
    }
  }
}"""

template_with_missing_sub = """{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "AWS CloudFormation template",
  "Resources": {
    "UnknownResource": {"Type": "AWS::Cloud9::EnvironmentEC2", "Properties": {}},
    "ApiGatewayRestApi": {
      "Type": "AWS::ApiGateway::RestApi",
      "Properties": {
        "Name": "test-api",
        "Description": {"Fn::Sub": "${UnknownResource}"},
        "EndpointConfiguration": {
          "Types": [
            "EDGE"
          ]
        }
      }
    }
  },
  "Outputs": {
  }
}"""


@mock_aws
def test_simple_apigateway_with_lambda_proxy():
    region = "us-east-1"
    apigw = boto3.client("apigateway", region_name=region)
    cf = boto3.client("cloudformation", region_name=region)
    awslambda = boto3.client("lambda", region_name=region)
    cf.create_stack(StackName="teststack", TemplateBody=template)
    #
    cf.describe_stacks(StackName="teststack")["Stacks"]
    resources = cf.describe_stack_resources(StackName="teststack")["StackResources"]
    api_id = [
        r["PhysicalResourceId"]
        for r in resources
        if r["ResourceType"] == "AWS::ApiGateway::RestApi"
    ][0]
    fn_name = [
        r["PhysicalResourceId"]
        for r in resources
        if r["LogicalResourceId"] == "HelloLambdaFunction"
    ][0]
    #
    # Verify Rest API was created
    api = apigw.get_rest_apis()["items"][0]
    assert api["id"] == api_id
    assert api["name"] == "dev-timeseries-service"
    #
    # Verify Gateway Resource was created
    paths = apigw.get_resources(restApiId=api_id)["items"]
    root_path = [p for p in paths if p["path"] == "/"][0]
    hello_path = [p for p in paths if p["path"] == "/hello"][0]
    assert hello_path["parentId"] == root_path["id"]
    #
    # Verify Gateway Method was created
    m = apigw.get_method(
        restApiId=api_id, resourceId=hello_path["id"], httpMethod="GET"
    )
    assert m["httpMethod"] == "GET"
    #
    # Verify a Gateway Deployment was created
    d = apigw.get_deployments(restApiId=api_id)["items"]
    assert len(d) == 1
    #
    # Verify Lambda function was created
    awslambda.get_function(FunctionName=fn_name)  # Will throw 404 if it doesn't exist
    #
    # Verify Lambda Permission was created
    policy = json.loads(awslambda.get_policy(FunctionName=fn_name)["Policy"])
    statement = policy["Statement"][0]
    assert (
        statement["FunctionName"]
        == f"arn:aws:lambda:us-east-1:123456789012:function:{fn_name}"
    )
    assert (
        statement["Condition"]["ArnLike"]["AWS:SourceArn"]
        == f"arn:aws:execute-api:us-east-1:123456789012:{api_id}/*/*"
    )


@mock_aws
@pytest.mark.filterwarnings("ignore:Tried to parse")
def test_apigateway_with_unknown_description():
    region = "us-east-1"
    apigw = boto3.client("apigateway", region_name=region)
    cf = boto3.client("cloudformation", region_name=region)
    cf.create_stack(StackName="teststack", TemplateBody=template_with_missing_sub)

    api = apigw.get_rest_apis()["items"][0]
    assert api["description"] == "${UnknownResource}"
