# frozen_string_literal: true

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

module Litany
  class RDSCluster < Resource
    include Taggable # not really taggable

    cfn_type 'AWS::RDS::DBCluster'
    parent_resource :service

    property :backup_retention, 7, 1..35, inherited: true # Supports 0, but changing to/from 0 can be disruptive and means there's no backups.
    property :backup_window, nil, [nil, String], inherited: true do |value|
      raise 'Backup window must be at least 30 minutes and formatted as hh24:mi-hh24:mi' unless value.nil? || /[0-9]{2}:[0-9]{2}-[0-9]{2}:[0-9]{2}/.match(value)
      value
    end
    property :encrypted, false, [true, false], inherited: true
    property :engine, :aurora, [:aurora, :aurora_mysql, :aurora_postgresql], inherited: true
    property :maintenance_window, nil, [nil, String], inherited: true do |value|
      raise 'Maintenance window must be at least 30 minutes and formatted as hh24:mi-hh24:mi' unless value.nil? || /(Mon|Tue|Wed|Thu|Fri|Sat|Sun):[0-9]{2}:[0-9]{2}-(Mon|Tue|Wed|Thu|Fri|Sat|Sun):[0-9]{2}:[0-9]{2}/.match(value)
      value
    end
    property :password, nil, [nil, String], inherited: true, secret: true
    property :port, 3306, [Integer], inherited: true
    property :snapshot, nil, [nil, String], inherited: true
    property :username, nil, [nil, String], inherited: true
    property :version, nil, [nil, String], inherited: true

    resource_reference KMSKey, :kms_key, inherited: true, required: false
    resource_reference RDSClusterParameterGroup, :cluster_parameters, required: false, inherited: true
    resource_reference RDSSubnetGroup, :subnet_group, inherited: true
    resource_references SecurityGroup, :security_group, required: false, inherited: true

    property :source, nil, [nil, String], inherited: true
    resource_reference Environment, :source_region, required: false, inherited: true

    validator :encryption_setup do
      encrypted true unless kms_key.nil?
    end

    validator :replication do
      if set_source?
        self.username = nil
        self.password = nil
      end
    end

    validator :snapshot do
      raise 'You must specify username and password unless snapshot is specified.' if snapshot.nil? && (username.nil? || password.nil?)
    end

    def default_tags
      {
        LitanyRDSClusterName: name
      }
    end

    def properties
      # TODO: Figure if I need to set DatabaseName or not
      # Implementing in other ways: AvailabilityZones
      props = {
        BackupRetentionPeriod: backup_retention,
        DBSubnetGroupName: ref(subnet_group),
        Engine: engine.tr('_', '-'),
        Port: port,
        StorageEncrypted: encrypted
      }

      props[:EngineVersion] = version unless version.nil?
      props[:KmsKeyId] = ref(kms_key, :Arn) if set_kms_key?
      props[:MasterUsername] = username unless username.nil?
      props[:MasterUserPassword] = password unless password.nil?
      props[:PreferredBackupWindow] = backup_window unless backup_window.nil?
      props[:PreferredMaintenanceWindow] = maintenance_window unless maintenance_window.nil?
      props[:SnapshotIdentifier] = snapshot unless snapshot.nil?
      props[:VpcSecurityGroupIds] = ref(security_groups) unless security_groups.empty?

      # This must be set if you are using Aurora. CloudFormation only supports allows ommission for Aurora (MySQL 5.6)
      props[:DBClusterParameterGroupName] = ref(cluster_parameters) if set_cluster_parameters? && cluster_parameters.parameters.count.positive?
      props[:DBClusterParameterGroupName] ||= 'default.aurora-postgresql9.6' if engine == :aurora_postgresql
      props[:DBClusterParameterGroupName] ||= 'default.aurora-mysql5.7' if engine == :aurora_mysql

      props[:ReplicationSourceIdentifier] = source if set_source?
      props[:SourceRegion] = source_region.region if set_source_region?

      props
    end

  end
end
