# frozen_string_literal: true

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

module Litany
  class Redshift < MetaResource
    include ServiceRoot
    include Stack

    child_resource RedshiftCluster, :cluster
    child_resource RedshiftParameterGroup, :parameter_group
    child_resource RedshiftSubnetGroup, :subnet_group

    flag :automatic_major_version_upgrades, false
    flag :encrypt, true
    flag :publicly_accessible, false

    property :cluster_name, nil, [nil, /^[a-z](?:[a-z0-9]|-(?!-)){0,61}(?:[a-z0-9]$|(?<!-)$)/]
    property :cluster_size, 2, 1..100
    property :db_name, 'dev', /^[a-z]{1,64}$/
    property :instance_type, 'dc2.large', ['ds2.xlarge', 'ds2.8xlarge', 'dc1.large', 'dc1.8xlarge', 'dc2.large', 'dc2.8xlarge', 'ra3.4xlarge', 'ra3.16xlarge']
    property :maintenance_window, nil, [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}/]
    property :port, 5439, 1150..65_535
    property :snapshot_retention, 7, 1..35
    property :username, 'root', /^[a-zA-Z][a-zA-Z0-9]{1,127}$/

    resource_collection IAMRole, :iam_role, required: false
    resource_collection SecurityGroup, :security_group, required: false

    resource_reference VPC, :vpc

    resource_references Environment, :only_in, required: false
    resource_references IAMRole, :role, required: false

    def access_sg
      security_group(:"#{name}_redshift_access")
    end

    def finalize_resource
      access_sg.description "Access to the #{name} Redshift Cluster"

      return unless set_iam_roles?

      permissions.trust service: 'redshift.amazonaws.com'
      role(permissions)
    end

    def ingress(source: nil, beanstalk: nil, environment: nil, ecs: nil)
      configs = [source.nil?, beanstalk.nil?, ecs.nil?]

      raise 'You must provide either a `source`, ecs cluster, or beanstalk environment.' if configs.count(true) == 3
      raise 'You may only provide one `source`, ecs cluster, or a beanstalk environment in the same `ingress` call.' unless configs.count(false) == 1
      raise 'You must specify both `beanstalk` and `environment` to allow ingress from a beanstalk environment' if !beanstalk.nil? && environment.nil?

      access_sg.ingress port: port, source: Beanstalk.new(beanstalk).beanstalk_environment(environment).reference_sg unless beanstalk.nil?
      deferred { access_sg.ingress port: port, source: ECSService.new(ecs).reference_sg } unless ecs.nil?
      access_sg.ingress port: port, source: source unless source.nil?
    end

    def permissions(&block)
      iam_role(:"#{name}_redshift", &block)
    end
  end
end
