# frozen_string_literal: true

require 'litany/mixins'
require 'litany/resource'

module Litany
  class LambdaFunction < Resource
    include ServiceRoot
    include Taggable
    include Metable

    cfn_type 'AWS::Lambda::Function'
    service_name_pattern '%s-lambda'

    property :code, nil, String
    property :description, nil, [nil, String]
    property :handler, 'index.handler', String
    property :memory_size, 128, 128..3_008 do |value|
      raise 'Lambda memory size must be from 128-3008 and a multiple of 64' unless value % 64 == 0
      value
    end
    property :rate, nil, [nil, Integer]
    property :runtime, 'nodejs6.10', %w(nodejs4.3 nodejs6.10 nodejs8.10 nodejs10.x nodejs12.x java8 python2.7 python3.6 dotnetcore1.0 dotnetcore2.0 go1.x)
    property :timeout, 3, 1..300

    property :environment, {}, Hash
    property :no_default_environment, false, [true, false]


    child_resource EventsRule, :event, automatic: :on_access
    child_resource InstanceProfileRole, :role
    child_resource LambdaPermission, :permissions, automatic: :on_access

    resource_collection KMSKey, :kms_key, required: false

    resource_reference VPC, :vpc, required: false
    resource_references SecurityGroup, :security_group, required: false

    validator(:vpc_config) do
      raise 'You must set both `vpc` and `security_groups` or neither.' if set_vpc? ^ set_security_groups?
    end

    def allow(actions:, resource:)
      role.allow(actions: actions, resource: resource)
    end

    def depends_on
      role.resource_name
    end

    def finalize_resource
      if set_rate?
        event.schedule "rate(#{rate} minute#{rate > 1 ? 's' : ''})"
        event.target_lambda self
        permissions.action 'lambda:InvokeFunction'
        permissions.service 'events.amazonaws.com'
        permissions.function self
        permissions.event event
      end
      role.trusted_services ['lambda.amazonaws.com']

      allow actions: ['logs:*'], resource: '*'
      allow actions: ['ec2:CreateNetworkInterface', 'ec2:DescribeNetworkInterfaces', 'ec2:DeleteNetworkInterface'], resource: '*' if set_vpc?
    end

    def compile_template
      template = project.get_lambda_template(code)
      metas = active_environment.compile_metas.merge(compile_metas.merge(compile_metas))
      output = template.render(Object.new, metas)
      {ZipFile:output.encode(output.encoding, universal_newline: true)}
    end

    def instance_profile
      # added for KMS Key allow compatibility, need a better solution for these things
      self
    end

    def properties
      # Unimplemented: DeadLetterConfig, FunctionName, KmsKeyArn, TracingConfig
      props = {
        Code: compile_template,
        Handler: handler,
        MemorySize: memory_size,
        Runtime: runtime,
        Timeout: timeout,
        Role: ref(role, :Arn)
      }

      default_environment = {
          AWSAccountId: {Ref: 'AWS::AccountId'},
          PROJECT: project.name,
          STAGE: project.stage,
      }

      props[:Environment] = {
          Variables: default_environment.merge(environment)
      } unless no_default_environment

      if set_vpc?
        props[:VpcConfig] = {
          SecurityGroupIds: ref(security_groups),
          SubnetIds: ref(vpc.subnets)
        }
      end

      props[:Description] = description if set_description?

      props
    end

    def default_tags
      {
          LitanyLambdaFunctionName: self.name
      }
    end
  end

end
