# frozen_string_literal: true

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

require 'litany/meta_resources/rds'

module Litany
  class RDSMssql < RDS

    child_resource IAMRole, :native_backup_role, automatic: :on_access

    property :engine, :sqlserver_se, [:sqlserver_ee, :sqlserver_se, :sqlserver_ex, :sqlserver_web]
    property :instance_type, 'db.r3.xlarge', [String], inherited: true do |value|
      raise "Invalid instance type #{value}. Must match `db.[class].[size]`" unless /db\.(?:t|m|r)[1-5]\.(?:[2-8]|10|16)?(?:micro|small|medium|large|xlarge)/.match(value)
      value
    end
    property :iops, nil, [1000..20_000, nil]
    property :license_model, :license_included, [:license_included, :bring_your_own_license]
    property :port, 1433, 1150..65_535 do |value|
      invalid_ports = [1434, 3389, 47_001] + (49_152..49_156).to_a
      raise 'SQLServer does not allow usage of ports 1434, 3389, 47001, or 49152-49156.' if mssql? && invalid_ports.include?(value)
      value
    end
    property :storage_size, '200', [String, 200..16_384], &:to_s
    property :storage_type, :gp2, [:gp2, :io1, nil]
    property :version, '12.00.5546.0.v1', ['13.00.4451.0.v1', '13.00.4422.0.v1', '13.00.2164.0.v1', '12.00.5546.0.v1', '12.00.5000.0.v1'] # only filling in 2016/2014 atm

    resource_collection DNSRecord, :dns_record, required: false
    resource_references S3Bucket, :native_backup_bucket, required: false

    validator :storage_configuration do
      valid_sizes = (2..163).collect { |interval| interval * 100 }
      raise 'For MSSQL storage size must be between 200 and 16,300 and evenly divisible by 100.' unless valid_sizes.include?(storage_size.to_i)

      if set_iops?
        valid_values = (1..20).collect { |interval| interval * 1000 }
        low = (storage_size.to_i / 1000.0).ceil * 1000
        raise "IOPs for MSSQL RDS must be between #{low.to_s_with_delim} and 20,000 evenly and divisible by 1000." unless valid_values.include?(iops) && iops >= low
        storage_type :io1
      end
    end

    def add_alias(name, zone)
      record = dns_record(name)
      record.type :cname
      deferred(step: :post_finalization) { record.target ref(instances.first, 'Endpoint.Address') }
      record.zone(zone)
      record
    end

    def finalize_resource
      super

      instance(name) if instances.count.zero?

      return unless set_native_backup_role? || set_native_backup_buckets?

      native_backup_role.trust service: 'rds.amazonaws.com'

      options_group.major_version = version.split('.')[0..1].join('.')
      options_group.description = "Options for #{name} SQL cluster."

      native_backup = options_group.option :"native_backup_for_#{name.snake_case}"
      native_backup.option 'SQLSERVER_BACKUP_RESTORE'
      native_backup.setting 'IAM_ROLE_ARN', ref(native_backup_role, :Arn)

      native_backup_buckets.each do |bucket|
        native_backup_role.allow(actions: ['s3:ListBucket', 's3:GetBucketLocation'], resource: ref(bucket, 'Arn'))
        native_backup_role.allow(actions: ['s3:GetObjectMetaData', 's3:GetObject', 's3:PutObject', 's3:ListMultipartUploadParts', 's3:AbortMultipartUpload'], resource: join([ref(bucket, 'Arn'), '*'], '/'))
      end
    end
  end
end
