# frozen_string_literal: true

require "active_support/concern"

module Decidim
  module TranslatableResource
    extend ActiveSupport::Concern

    included do
      after_create :machine_translation
      after_update :machine_translation

      validate :translatable_fields_are_hashes

      def self.translatable_fields(*list)
        @translatable_fields = list

        @translatable_fields.each do |field|
          method_name = "#{field}="

          # We are overriding the attribute setter method so that we can reuse the
          # machine translations. This is to fix a bug encountered when updating
          # the resource from a FormObject. The FormObject on the `#create`
          # action in the controller does not have the machine translations loaded,
          # so they are effectively lost whenever a resource is updated.
          #
          # This overriding allows us to keep the old machine translations, so
          # that we skip some translations requests.
          define_method(method_name) do |new_value|
            return super(new_value) if attributes[field.to_s].nil?
            return super(new_value) unless [new_value, attributes[field.to_s]].all?(Hash)
            return super(new_value) if new_value.has_key?("machine_translations")

            original_value = attributes[field.to_s]

            new_value = new_value.merge("machine_translations" => original_value["machine_translations"]) if original_value.has_key?("machine_translations")

            super(new_value)
          end
        end
      end

      def self.translatable_fields_list
        @translatable_fields
      end

      # Fires a job to start the machine translation process, only if the
      # service is properly configured and the organization has machine
      # translations enabled.
      def machine_translation
        return unless Decidim.machine_translation_service_klass

        organization = try(:organization)
        return if organization && !organization.enable_machine_translations
        return if try(:enable_machine_translations) == false

        Decidim::MachineTranslationResourceJob.set(wait: Decidim.config.machine_translation_delay).perform_later(
          self,
          translatable_previous_changes,
          I18n.locale.to_s
        )
      end

      def translatable_previous_changes
        previous_changes.slice(*self.class.translatable_fields_list)
      end

      def translatable_fields_are_hashes
        self.class.translatable_fields_list.each do |field|
          value = send(field).presence
          next if value.nil? || value.is_a?(Hash)

          errors.add(field, :invalid)
        end
      end

      # Public: Returns the original language in which the resource was created or
      #         the organization's default locale.
      def content_original_language
        field_name = self.class.translatable_fields_list.first
        field_value = self[field_name]
        return field_value.except("machine_translations").keys.first if field_value && field_value.except("machine_translations").keys.count == 1

        organization.default_locale
      end
    end
  end
end
