# frozen_string_literal: true

require "sassc"

module Decidim
  module DecidimAwesome
    module Admin
      class ConfigForm < Decidim::Form
        include ActionView::Helpers::SanitizeHelper

        attribute :allow_images_in_full_editor, Boolean
        attribute :allow_images_in_small_editor, Boolean
        attribute :allow_images_in_proposals, Boolean
        attribute :use_markdown_editor, Boolean
        attribute :allow_images_in_markdown_editor, Boolean
        attribute :auto_save_forms, Boolean
        attribute :scoped_styles, Hash
        attribute :proposal_custom_fields, Hash
        attribute :scoped_admins, Hash
        attribute :menu, Array[MenuForm]
        attribute :intergram_for_admins, Boolean
        attribute :intergram_for_admins_settings, IntergramForm
        attribute :intergram_for_public, Boolean
        attribute :intergram_for_public_settings, IntergramForm
        attribute :validate_title_min_length, Integer, default: 15
        attribute :validate_title_max_caps_percent, Integer, default: 25
        attribute :validate_title_max_marks_together, Integer, default: 1
        attribute :validate_title_start_with_caps, Boolean, default: true
        attribute :validate_body_min_length, Integer, default: 15
        attribute :validate_body_max_caps_percent, Integer, default: 25
        attribute :validate_body_max_marks_together, Integer, default: 1
        attribute :validate_body_start_with_caps, Boolean, default: true
        attribute :additional_proposal_sortings, Array, default: Decidim::DecidimAwesome.possible_additional_proposal_sortings

        # collect all keys anything not specified in the params (UpdateConfig command ignores it)
        attr_accessor :valid_keys

        validate :css_syntax, if: ->(form) { form.scoped_styles.present? }
        validate :json_syntax, if: ->(form) { form.proposal_custom_fields.present? }
        validates :validate_title_min_length, presence: true, numericality: { greater_than_or_equal_to: 1, less_than_or_equal_to: 100 }
        validates :validate_title_max_caps_percent, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
        validates :validate_title_max_marks_together, presence: true, numericality: { greater_than_or_equal_to: 1 }
        validates :validate_body_min_length, presence: true, numericality: { greater_than_or_equal_to: 0 }
        validates :validate_body_max_caps_percent, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }
        validates :validate_body_max_marks_together, presence: true, numericality: { greater_than_or_equal_to: 1 }

        # TODO: validate non general admins are here

        def self.from_params(params, additional_params = {})
          instance = super(params, additional_params)
          instance.valid_keys = params.keys.map(&:to_sym) || []
          instance.sanitize_labels!
          instance
        end

        def additional_proposal_sorting_labels
          Decidim::DecidimAwesome.possible_additional_proposal_sortings.index_by do |sorting|
            I18n.t(sorting, scope: "decidim.proposals.proposals.orders")
          end
        end

        def css_syntax
          scoped_styles.each do |key, code|
            next unless code

            SassC::Engine.new(code).render
          rescue SassC::SyntaxError => e
            errors.add(:scoped_styles, I18n.t("config.form.errors.incorrect_css", key: key, scope: "decidim.decidim_awesome.admin"))
            errors.add(key.to_sym, e.message)
          end
        end

        def json_syntax
          proposal_custom_fields.each do |key, code|
            next unless code

            JSON.parse(code)
          rescue JSON::ParserError => e
            errors.add(:scoped_styles, I18n.t("config.form.errors.incorrect_json", key: key, scope: "decidim.decidim_awesome.admin"))
            errors.add(key.to_sym, e.message)
          end
        end

        # formBuilder has a bug and do not sanitize text if users copy/paste text with format in the label input
        def sanitize_labels!
          return unless proposal_custom_fields

          proposal_custom_fields.transform_values! do |code|
            next unless code

            json = JSON.parse(code)
            json.map! do |item|
              item["label"] = strip_tags(item["label"])
              item
            end
            JSON.generate(json)
          rescue JSON::ParserError
            code
          end
        end
      end
    end
  end
end