# frozen_string_literal: true

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

module Litany

  class BaseInstance < Resource
    property :detailed_monitoring, true, [true, false], inherited: true
    property :ebs_optimized, true, [true, false], inherited: true
    property :ephemeral_volumes, 0, 0..26
    property :instance_type, 'm4.large', [String], inherited: true
    property :key_pair, nil, [nil, String, Symbol], inherited: true
    property :root_volume_size, 50, 4..16_384
    property :device_prefix, 'sd', ['sd', 'xvd']

    resource_reference Image, :image, inherited: true
    resource_reference InstanceProfile, :instance_profile, inherited: true

    resource_references SecurityGroup, :security_group, inherited: true, required: false

    def compile_userdata
      userdata = image.userdata
      template = project.get_userdata_template(userdata.template)
      metas = active_environment.compile_metas.merge(userdata.compile_metas.merge(compile_metas))
      output = template.render(Object.new, metas)
      {'Fn::Base64': output.encode(output.encoding, universal_newline: true)}
    end
  end

  class AutoScalingLaunchConfiguration < BaseInstance
    cfn_type 'AWS::AutoScaling::LaunchConfiguration'

    resource_collection AutoScalingVolume, :volume, required: false

    resource_reference VPC, :vpc, inherited: true

    def properties
      # TODO: BlockDeviceMappings
      # Not implementing: ClassicLinkVPCId, ClassicLinkVPCSecurityGroups, InstanceId, KernelId, RamDiskId, SpotPrice, PlacementTenancy
      props = {
        AssociatePublicIpAddress: vpc.subnets.any?(&:public_ips),
        BlockDeviceMappings: [
          {
            DeviceName: "/dev/#{device_prefix}a#{device_prefix == 'sd' ? '1' : ''}",
            Ebs: {
              # Not setting encrypted here as it has to be inherited from the root AMI snapshot.
              DeleteOnTermination: true,
              VolumeSize: root_volume_size,
              VolumeType: :gp2
            }
          }
        ],
        EbsOptimized: ebs_optimized,
        IamInstanceProfile: ref(instance_profile),
        ImageId: image.ami,
        InstanceMonitoring: detailed_monitoring,
        InstanceType: instance_type,
      }

      if ephemeral_volumes.positive?
        device_character = 'b'.ord

        props[:BlockDeviceMappings] += Array.new(ephemeral_volumes) do |index|
          {
            DeviceName: "/dev/#{device_prefix}#{(device_character + index).chr}",
            VirtualName: "ephemeral#{index}"
          }
        end
      end

      props[:BlockDeviceMappings] += volumes

      props[:KeyName] = key_pair if set_key_pair?
      props[:SecurityGroups] = ref(security_groups) unless security_groups.empty?
      props[:UserData] = compile_userdata unless image.userdata.template.nil?

      props
    end
  end
end
