# frozen_string_literal: true
class AnswerFormatValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    send(record.question.input_type, record, attribute, value)
  end

  private

    def text record, attribute, value
      clean_val = value.to_s.strip.delete("\r")
      return if clean_val.length.between?(1, 1000)

      if clean_val.blank?
        record.errors[attribute] << (options[:message] || "Please enter an answer.")
      end

      if clean_val.length > 1000
        record.errors[attribute] << (options[:message] || "The character limit for this answer is 1000.")
      end
    end

    def radio record, attribute, value
      return unless value.to_s.strip.blank?

      record.errors[attribute] << (options[:message] || "Please select an answer.")
    end

    def checkbox record, attribute, value
      return unless value.nil? || Array(value).join.blank?

      record.errors[attribute] << (options[:message] || "Please select an answer.")
    end

    def live_code record, attribute, value
      seed = (Question.find_by(id: record.question_id) || Question.new).input_options

      return unless value.nil? || value.values.join.blank? || !match_seed?(value, seed)

      record.errors[attribute] << (options[:message] || live_code_error_message(value))
    end

    def with_other record, attribute, value
      return if value.present? && with_other_check(value)

      record.errors[attribute] << (options[:message] || "Please select or provide an answer.")
    end
    alias radio_other with_other
    alias checkbox_other with_other

    #################################

    def with_other_check value
      return false unless value.respond_to? :keys
      return false if Array(value[:options]).join.blank?
      return false if value[:options].include?('other') && value[:other].to_s.blank?
      true
    end

    def live_code_error_message value
      if value.present? && value.keys.count == 1
        return "Please check that you will come back to complete the code example."
      end
      "You must write comments or code in one of the textareas to progress."
    end

    def match_seed? value, seed
      s_value = value.stringify_keys
      s_seed = seed.stringify_keys
      keys = s_value.merge(s_seed).keys.uniq

      matches = keys.inject([]) do |memo, k|
        memo << (s_value[k].to_s.strip == s_seed[k].to_s.strip)
      end

      matches.include? false
    end
end
