class Communication::SparkpostConfig < ApplicationRecord
  include Validatable

  audited

  enum event: [:sending, :bounce, :tracking]

  attr_accessor :save_duplicate

  belongs_to :school, inverse_of: :communication_sparkpost_configs

  validates :event, :domain, presence: true

  validate :sending_domain_format, if: :new_record?
  validate :create_domain, if: :new_record?

  before_save :link_tracking_and_sending, if: :tracking?

  before_destroy :delete_from_sparkpost, unless: :multiple_domains?

  def verify
    self.verified = if sending?
      response = domain_service(:verify)
      response['results'] && response['results']['dkim_status'] == 'valid'
    else
      response = domain_service(:cname_verify)
      response['results'] && response['results']['cname_status'] == 'valid'
    end

    add_custom_error(:verification, 'was unsucessful') unless verified
    save
  end

  def dkim_record
    return if id.nil?
    return {} unless (response = domain_service(:show))['results']

    response['results']['dkim']
  end

  private
    def sending_domain_format
      return if domain.nil?

      requirements = {
        'must be a-z or A-Z or 0-9 and hyphen (-)' => /^[A-Za-z0-9\-.]*$/,
        'must be between 1 and 63 characters long' => /^.{1,63}$/,
        'must not start or end with a hyphen(-)' => /^(?!-).*(?<!-)$/,
        'TLD must be from 2-6 characters long' => /^(\w+\.)?[a-z0-9-]+\.([a-z]{2,6})?$/
      }

      illegal_domains = ['gmail.com', 'hotmail.com', 'outlook.com', 'yahoo.com']
      illegal_domains.each do |illegal_domain|
        message = "must not be #{illegal_domain}"
        requirements[message] = Regexp.new("^(?!.*#{illegal_domain})")
      end

      sycamore_domains = [
        'sycamoreleaf.com',
        'sycamoreschool.com',
        'sycamore.school',
        'sycamoresupport.com',
        'sycamorecampus.com',
        'sycamoreeducation.com'
      ]
      sycamore_domains.each do |sycamore_domain|
        message = "Please enter your school's domain name"
        regex = Regexp.new("^(?!.*#{sycamore_domain})")
        next if domain.match(regex)

        requirements[message] = regex
      end

      requirements.each do |message, regex|
        errors.add(:domain, message) unless domain.match(regex)
      end
    end

    def create_domain
      return if errors.present?

      response = domain_service(:create)
      return if save_duplicate || response['errors'].blank?

      response['errors'].each { |e| errors.add(:sparkpost, e['description']) }
    end

    def link_tracking_and_sending
      return unless verified_changed?(from: false, to: true)

      sending = school.communication_sparkpost_sending_config
      return unless sending

      domain_service(:link, sending)
    end

    def delete_from_sparkpost
      # check domain across sites before deleting from Sparkpost
      return if self.class.where(domain: domain).count > 1

      domain_service(:delete)
    end

    def domain_service(method, record=nil)
      Sparkpost::DomainService.call(method, record || self)
    end

    def multiple_domains?
      self.class.where(domain: domain).count > 1
    end
end
