# frozen_string_literal: true

module Bulkrax
  # Import Behavior for Entry classes
  module ImportBehavior # rubocop:disable Metrics/ModuleLength
    extend ActiveSupport::Concern

    def build_for_importer
      begin
        build_metadata
        unless self.importerexporter.validate_only
          raise CollectionsCreatedError unless collections_created?
          @item = factory.run!
          add_user_to_permission_templates! if self.class.to_s.include?("Collection")
          parent_jobs if self.parsed_metadata[related_parents_parsed_mapping].present?
          child_jobs if self.parsed_metadata[related_children_parsed_mapping].present?
        end
      rescue RSolr::Error::Http, CollectionsCreatedError => e
        raise e
      rescue StandardError => e
        status_info(e)
      else
        status_info
      ensure
        self.save!
      end
      return @item
    end

    def add_user_to_permission_templates!
      permission_template = Hyrax::PermissionTemplate.find_or_create_by!(source_id: @item.id)

      Hyrax::PermissionTemplateAccess.find_or_create_by!(
        permission_template_id: permission_template.id,
        agent_id: user.user_key,
        agent_type: 'user',
        access: 'manage'
      )
      Hyrax::PermissionTemplateAccess.find_or_create_by!(
        permission_template_id: permission_template.id,
        agent_id: 'admin',
        agent_type: 'group',
        access: 'manage'
      )

      @item.reset_access_controls!
    end

    def parent_jobs
      self.parsed_metadata[related_parents_parsed_mapping].each do |parent_identifier|
        next if parent_identifier.blank?

        PendingRelationship.create!(child_id: self.identifier, parent_id: parent_identifier, bulkrax_importer_run_id: importerexporter.last_run.id, order: self.id)
      end
    end

    def child_jobs
      self.parsed_metadata[related_children_parsed_mapping].each do |child_identifier|
        next if child_identifier.blank?

        PendingRelationship.create!(parent_id: self.identifier, child_id: child_identifier, bulkrax_importer_run_id: importerexporter.last_run.id, order: self.id)
      end
    end

    def find_collection_ids
      self.collection_ids
    end

    # override this in a sub-class of Entry to ensure any collections have been created before building the work
    def collections_created?
      true
    end

    def build_metadata
      raise StandardError, 'Not Implemented'
    end

    def rights_statement
      parser.parser_fields['rights_statement']
    end

    # try and deal with a couple possible states for this input field
    def override_rights_statement
      %w[true 1].include?(parser.parser_fields['override_rights_statement'].to_s)
    end

    def add_rights_statement
      self.parsed_metadata['rights_statement'] = [parser.parser_fields['rights_statement']] if override_rights_statement || self.parsed_metadata['rights_statement'].blank?
    end

    def add_visibility
      self.parsed_metadata['visibility'] = importerexporter.visibility if self.parsed_metadata['visibility'].blank?
    end

    def add_admin_set_id
      self.parsed_metadata['admin_set_id'] = importerexporter.admin_set_id if self.parsed_metadata['admin_set_id'].blank?
    end

    def add_collections
      return if find_collection_ids.blank?

      self.parsed_metadata['member_of_collections_attributes'] = {}
      find_collection_ids.each_with_index do |c, i|
        self.parsed_metadata['member_of_collections_attributes'][i.to_s] = { id: c }
      end
    end

    # Attempt to sanitize Questioning Authority URI values for configured controlled fields of common
    # data entry mistakes. Controlled URI values are only valid if they are an exact match.
    # Example:
    #   Valid value:     http://rightsstatements.org/vocab/InC/1.0/
    #   Provided value:  https://rightsstatements.org/vocab/InC/1.0
    #   Sanitized value: http://rightsstatements.org/vocab/InC/1.0/ ("s" from "https" removed, trailing "/" added)
    #
    # @return [Boolean] true if all controlled URI values are sanitized successfully
    def sanitize_controlled_uri_values!
      Bulkrax.qa_controlled_properties.each do |field|
        next if parsed_metadata[field].blank?

        parsed_metadata[field].each_with_index do |value, i|
          next if value.blank?

          if (validated_uri_value = validate_value(value, field))
            parsed_metadata[field][i] = validated_uri_value
          else
            debug_msg = %(Unable to locate active authority ID "#{value}" in config/authorities/#{field.pluralize}.yml)
            Rails.logger.debug(debug_msg)
            error_msg = %("#{value}" is not a valid and/or active authority ID for the :#{field} field)
            raise ::StandardError, error_msg
          end
        end
      end

      true
    end

    # @param value [String] value to validate
    # @param field [String] name of the controlled property
    # @return [String, nil] validated URI value or nil
    def validate_value(value, field)
      if value.match?(::URI::DEFAULT_PARSER.make_regexp)
        value = value.strip.chomp
        # add trailing forward slash unless one is already present
        value << '/' unless value.match?(%r{/$})
      end

      valid = if active_id_for_authority?(value, field)
                true
              else
                value.include?('https') ? value.sub!('https', 'http') : value.sub!('http', 'https')
                active_id_for_authority?(value, field)
              end

      valid ? value : nil
    end

    # @param value [String] value to check
    # @param field [String] name of the controlled property
    # @return [Boolean] provided value is a present, active authority ID for the provided field
    def active_id_for_authority?(value, field)
      field_service = ('Hyrax::' + "#{field}_service".camelcase).constantize
      active_authority_ids = field_service.new.active_elements.map { |ae| ae['id'] }

      active_authority_ids.include?(value)
    end

    def factory
      @factory ||= Bulkrax::ObjectFactory.new(attributes: self.parsed_metadata,
                                              source_identifier_value: identifier,
                                              work_identifier: parser.work_identifier,
                                              related_parents_parsed_mapping: parser.related_parents_parsed_mapping,
                                              replace_files: replace_files,
                                              user: user,
                                              klass: factory_class,
                                              importer_run_id: importerexporter.last_run.id,
                                              update_files: update_files)
    end

    def factory_class
      fc = if self.parsed_metadata&.[]('model').present?
             self.parsed_metadata&.[]('model').is_a?(Array) ? self.parsed_metadata&.[]('model')&.first : self.parsed_metadata&.[]('model')
           elsif self.mapping&.[]('work_type').present?
             self.parsed_metadata&.[]('work_type').is_a?(Array) ? self.parsed_metadata&.[]('work_type')&.first : self.parsed_metadata&.[]('work_type')
           else
             Bulkrax.default_work_type
           end

      # return the name of the collection or work
      fc.tr!(' ', '_')
      fc.downcase! if fc.match?(/[-_]/)
      fc.camelcase.constantize
    rescue NameError
      nil
    rescue
      Bulkrax.default_work_type.constantize
    end
  end
end