# frozen_string_literal: true

# Service class that holds helper methods that can be used to validate theme settings.
class ThemeSettingsValidator
  class << self
    def is_value_present?(value)
      !value.nil?
    end

    def is_valid_value_type?(value, type)
      case type
      when types[:integer]
        value.is_a?(Integer)
      when types[:float]
        value.is_a?(Integer) || value.is_a?(Float)
      when types[:bool]
        value.is_a?(TrueClass) || value.is_a?(FalseClass)
      when types[:list], types[:icon]
        value.is_a?(String)
      when types[:objects]
        value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) }
      else
        true
      end
    end

    def validate_value(value, type, opts)
      errors = []

      errors.concat(validate_resolve_group_membership(opts, type))

      case type
      when types[:enum]
        if opts[:choices].exclude?(value) && opts[:choices].map(&:to_s).exclude?(value)
          errors << I18n.t(
            "themes.settings_errors.enum_value_not_valid",
            choices: opts[:choices].join(", "),
          )
        end
      when types[:integer], types[:float]
        validate_value_in_range!(
          value,
          min: opts[:min],
          max: opts[:max],
          errors:,
          translation_prefix: "number",
        )
      when types[:string]
        validate_value_in_range!(
          value.to_s.length,
          min: opts[:min],
          max: opts[:max],
          errors:,
          translation_prefix: "string",
        )
      when types[:objects]
        errors.concat(
          SchemaSettingsObjectValidator.validate_objects(schema: opts[:schema], objects: value),
        )
      end

      errors
    end

    def validate_resolve_group_membership(opts, type)
      errors = []
      if opts[:resolve_group_membership]
        if type != types[:list]
          errors << I18n.t("themes.settings_errors.resolve_group_membership_requires_list")
        elsif opts[:list_type] != "group"
          errors << I18n.t("themes.settings_errors.resolve_group_membership_requires_group_list")
        end
      end

      if type == types[:objects]
        errors.concat(validate_object_schema_resolve_group_membership(opts[:schema]))
      end

      errors
    end

    private

    def types
      ThemeSetting.types
    end

    def validate_object_schema_resolve_group_membership(schema)
      errors = []
      return errors if schema.blank?

      schema[:properties].each do |property_name, property_attributes|
        if property_attributes[:resolve_group_membership] && property_attributes[:type] != "groups"
          errors << I18n.t(
            "themes.settings_errors.resolve_group_membership_requires_groups_property",
            property: property_name,
          )
        end

        if property_attributes[:type] == "objects"
          errors.concat(
            validate_object_schema_resolve_group_membership(property_attributes[:schema]),
          )
        end
      end

      errors
    end

    def validate_value_in_range!(value, min:, max:, errors:, translation_prefix:)
      if min && max && max != Float::INFINITY && !(min..max).include?(value)
        errors << I18n.t(
          "themes.settings_errors.#{translation_prefix}_value_not_valid_min_max",
          min: min,
          max: max,
        )
      elsif min && value < min
        errors << I18n.t(
          "themes.settings_errors.#{translation_prefix}_value_not_valid_min",
          min: min,
        )
      elsif max && value > max
        errors << I18n.t(
          "themes.settings_errors.#{translation_prefix}_value_not_valid_max",
          max: max,
        )
      end
    end
  end
end
