class ResourceImportFile < ApplicationRecord
  include Statesman::Adapters::ActiveRecordQueries[
    transition_class: ResourceImportFileTransition,
    initial_state: ResourceImportFileStateMachine.initial_state
  ]
  include ImportFile
  default_scope { order("resource_import_files.id DESC") }
  scope :not_imported, -> { in_state(:pending) }
  scope :stucked, -> { in_state(:pending).where("resource_import_files.created_at < ?", 1.hour.ago) }

  has_one_attached :attachment
  validates :default_shelf_id, presence: true, if: proc { |model| model.edit_mode == "create" }
  belongs_to :user
  belongs_to :default_shelf, class_name: "Shelf", optional: true
  has_many :resource_import_results, dependent: :destroy
  has_many :resource_import_file_transitions, autosave: false, dependent: :destroy

  attr_accessor :mode, :library_id

  def state_machine
    ResourceImportFileStateMachine.new(self, transition_class: ResourceImportFileTransition)
  end

  delegate :can_transition_to?, :transition_to!, :transition_to, :current_state,
    to: :state_machine

  def import_start
    case edit_mode
    when "create"
      import
    when "update"
      modify
    when "destroy"
      remove
    when "update_relationship"
      update_relationship
    else
      import
    end
  end

  def import
    transition_to!(:started)
    num = {
      manifestation_imported: 0,
      item_imported: 0,
      manifestation_found: 0,
      item_found: 0,
      failed: 0
    }
    rows = open_import_file(create_import_temp_file(attachment))
    rows.shift
    # if [field['manifestation_id'], field['manifestation_identifier'], field['isbn'], field['original_title']].reject{|f|
    #  f.to_s.strip == ''
    # }.empty?
    #  raise "You should specify isbn or original_title in the first line"
    # end
    row_num = 1

    ResourceImportResult.create!(resource_import_file_id: id, body: (%w[ imported_manifestation_id imported_item_id ] + rows.headers).join("\t"))
    rows.each do |row|
      row_num += 1
      import_result = ResourceImportResult.new(resource_import_file_id: id)
      if row["dummy"].to_s.strip.present?
        import_result.error_message = "line #{row_num}: #{I18n.t('import.dummy')}"
        import_result.body = ([ nil, nil ] + row.fields).join("\t")
        import_result.save!
        next
      end

      item_identifier = row["item_identifier"].to_s.strip
      item = Item.find_by(item_identifier: item_identifier)
      if item
        import_result.item = item
        import_result.manifestation = item.manifestation
        import_result.error_message = "line #{row_num}: #{I18n.t('import.item_found')}"
        import_result.body = ([ item.manifestation.id, item.id ] + row.fields).join("\t")
        import_result.save!
        num[:item_found] += 1
        next
      end

      if row["manifestation_identifier"].present?
        manifestation = Manifestation.find_by(manifestation_identifier: row["manifestation_identifier"].to_s.strip)
      end

      unless manifestation
        if row["manifestation_id"].present?
          manifestation = Manifestation.find_by(id: row["manifestation_id"].to_s.strip)
        end
      end

      unless manifestation
        if row["iss_itemno"].present?
          iss_itemno = URI.parse(row["iss_itemno"]).path.gsub(/^\//, "")
          manifestation = NdlBibIdRecord.find_by(body: iss_itemno).manifestation
        end
      end

      unless manifestation
        if row["doi"].present?
          doi = URI.parse(row["doi"].downcase).path.gsub(/^\//, "")
          manifestation = DoiRecord.find_by(body: doi)&.manifestation
        end
      end

      unless manifestation
        if row["jpno"].present?
          jpno = row["jpno"].to_s.strip
          manifestation = JpnoRecord.find_by(body: jpno)&.manifestation
        end
      end

      unless manifestation
        if row["ncid"].present?
          ncid = row["ncid"].to_s.strip
          manifestation = NcidRecord.find_by(body: ncid)&.manifestation
        end
      end

      unless manifestation
        if row["lccn"].present?
          lccn = row["lccn"].to_s.strip
          manifestation = LccnRecord.find_by(body: lccn).manifestation
        end
      end

      unless manifestation
        if row["isbn"].present?
          row["isbn"].to_s.split("//").each do |isbn|
            m = IsbnRecord.find_by(body: Lisbn.new(isbn).isbn13)&.manifestations&.first
            if m
              if m.series_statements.exists?
                manifestation = m
              end
            else
              import_result.error_message = "line #{row_num}: #{I18n.t('import.isbn_invalid')}"
            end
          end
        end
      end

      if manifestation
        import_result.error_message = "line #{row_num}: #{I18n.t('import.manifestation_found')}"
        num[:manifestation_found] += 1
      end

      if row["original_title"].blank?
        unless manifestation
          begin
            if row["jpno"].present?
              manifestation = Manifestation.import_from_ndl_search(jpno: row["jpno"])
            end

            if row["ncid"].present?
              manifestation = Manifestation.import_from_cinii_books(ncid: row["ncid"])
            end

            row["isbn"].to_s.split("//").each do |isbn|
              lisbn = Lisbn.new(isbn)
              manifestation = Manifestation.import_from_ndl_search(isbn: lisbn.isbn13) if lisbn.isbn13
            end

            if manifestation
              num[:manifestation_imported] += 1
            end
          rescue EnjuNdl::InvalidIsbn
            manifestation = nil
            import_result.error_message = "line #{row_num}: #{I18n.t('import.isbn_invalid')}"
          rescue EnjuNdl::RecordNotFound, EnjuNii::RecordNotFound
            manifestation = nil
            import_result.error_message = "line #{row_num}: #{I18n.t('import.isbn_record_not_found')}"
          end
        end
        if manifestation.nil? && row["ndl_bib_id"]
          manifestation = Manifestation.import_ndl_bib_id("R100000002-I#{row['ndl_bib_id']}")
          if manifestation
            num[:manifestation_imported] += 1
          end
        end
      end

      unless manifestation
        manifestation = fetch(row)
        num[:manifestation_imported] += 1 if manifestation
      end
      import_result.manifestation = manifestation

      if manifestation
        manifestation.reload

        ResourceImportFile.import_manifestation_custom_value(row, manifestation).each do |value|
          value.update!(manifestation: manifestation)
        end

        item = nil
        if item_identifier.present? || row["shelf"].present? || row["call_number"].present?
          item = create_item(row, manifestation)
        else
          if manifestation.fulltext_content?
            item = create_item(row, manifestation)
            item.circulation_status = CirculationStatus.find_by(name: "Available On Shelf")
            begin
              item.acquired_at = Time.zone.parse(row["acquired_at"].to_s.strip)
            rescue ArgumentError
            end
          end
          num[:failed] += 1
        end

        if item
          ResourceImportFile.import_item_custom_value(row, item).each do |value|
            value.update!(item: item)
          end

          import_result.item = item
        end
      else
        num[:failed] += 1
      end

      import_result.body = ([ manifestation.try(:id), item.try(:id) ] + row.fields).join("\t")
      import_result.save!
      num[:item_imported] += 1 if import_result.item
    end

    Sunspot.commit
    rows.close
    transition_to!(:completed)
    mailer = ResourceImportMailer.completed(self)
    send_message(mailer)
    Rails.cache.write("manifestation_search_total", Manifestation.search.total)
    num
  rescue StandardError => e
    self.error_message = "line #{row_num}: #{e.message}"
    save
    transition_to!(:failed)
    mailer = ResourceImportMailer.failed(self)
    send_message(mailer)
    raise e
  end

  def self.import_work(title, agents, options = { edit_mode: "create" })
    work = Manifestation.new(title)
    work.save
    work.creators = agents.uniq unless agents.empty?
    work
  end

  def self.import_expression(work, agents, options = { edit_mode: "create" })
    expression = work
    expression.save
    expression.contributors = agents.uniq unless agents.empty?
    expression
  end

  def self.import_manifestation(expression, agents, options = {}, edit_options = { edit_mode: "create" })
    manifestation = expression
    manifestation.during_import = true
    manifestation.reload
    manifestation.update!(options)
    manifestation.publishers = agents.uniq unless agents.empty?
    manifestation.reload
    manifestation
  end

  def import_marc(marc_type)
    file = attachment.download
    case marc_type
    when "marcxml"
      reader = MARC::XMLReader.new(file)
    else
      reader = MARC::Reader.new(file)
    end
    file.close

    # when 'marc_xml_url'
    #  url = URI(params[:marc_xml_url])
    #  xml = open(url).read
    #  reader = MARC::XMLReader.new(StringIO.new(xml))
    # end

    # TODO
    reader.each do |record|
      manifestation = Manifestation.new(original_title: expression.original_title)
      manifestation.carrier_type = CarrierType.find(1)
      manifestation.frequency = Frequency.find(1)
      manifestation.language = Language.find(1)
      manifestation.save

      full_name = record["700"]["a"]
      publisher = Agent.find_by(full_name: record["700"]["a"])
      unless publisher
        publisher = Agent.new(full_name: full_name)
        publisher.save
      end
      manifestation.publishers << publisher
    end
  end

  def self.import
    ResourceImportFile.not_imported.each do |file|
      file.import_start
    end
  rescue StandardError
    Rails.logger.info "#{Time.zone.now} importing resources failed!"
  end

  # def import_jpmarc
  #  marc = NKF::nkf('-wc', self.db_file.data)
  #  marc.split("\r\n").each do |record|
  #  end
  # end

  def modify
    transition_to!(:started)
    rows = open_import_file(create_import_temp_file(attachment))
    rows.shift
    row_num = 1

    ResourceImportResult.create!(resource_import_file_id: id, body: rows.headers.join("\t"))
    rows.each do |row|
      row_num += 1
      import_result = ResourceImportResult.create!(resource_import_file_id: id, body: row.fields.join("\t"))
      item = Item.find_by(item_identifier: row["item_identifier"].to_s.strip) if row["item_identifier"].to_s.strip.present?
      unless item
        item = Item.find_by(id: row["item_id"].to_s.strip) if row["item_id"].to_s.strip.present?
      end

      if item
        if item.manifestation
          fetch(row, edit_mode: "update")
          item = update_item(item, row)
        end

        ResourceImportFile.import_item_custom_value(row, item).each do |value|
          value.update!(item: item)
        end
        ResourceImportFile.import_manifestation_custom_value(row, item.manifestation).each do |value|
          value.update!(manifestation: item.manifestation)
        end

        item.manifestation.reload
        item.save!
        import_result.item = item
      else
        manifestation_identifier = row["manifestation_identifier"].to_s.strip
        manifestation = Manifestation.find_by(manifestation_identifier: manifestation_identifier) if manifestation_identifier.present?
        manifestation ||= Manifestation.find_by(id: row["manifestation_id"])
        if manifestation
          fetch(row, edit_mode: "update")
          ResourceImportFile.import_manifestation_custom_value(row, manifestation).each do |value|
            value.update!(manifestation: manifestation)
          end
          import_result.manifestation = manifestation
        end
      end
      import_result.save!
    end
    transition_to!(:completed)
    mailer = ResourceImportMailer.completed(self)
    send_message(mailer)
  rescue StandardError => e
    self.error_message = "line #{row_num}: #{e.message}"
    save
    transition_to!(:failed)
    mailer = ResourceImportMailer.failed(self)
    send_message(mailer)
    raise e
  end

  def remove
    transition_to!(:started)
    rows = open_import_file(create_import_temp_file(attachment))
    rows.shift
    row_num = 1

    rows.each do |row|
      row_num += 1
      item = Item.find_by(item_identifier: row["item_identifier"].to_s.strip) if row["item_identifier"].to_s.strip.present?
      unless item
        item = Item.find_by(id: row["item_id"].to_s.strip) if row["item_id"].to_s.strip.present?
      end

      if item
        item.destroy if item.removable?
      end
    end
    transition_to!(:completed)
    mailer = ResourceImportMailer.completed(self)
    send_message(mailer)
  rescue StandardError => e
    self.error_message = "line #{row_num}: #{e.message}"
    save
    transition_to!(:failed)
    mailer = ResourceImportMailer.failed(self)
    send_message(mailer)
    raise e
  end

  def update_relationship
    transition_to!(:started)
    rows = open_import_file(create_import_temp_file(attachment))
    rows.shift
    row_num = 1

    rows.each do |row|
      item = Item.find_by(item_identifier: row["item_identifier"].to_s.strip) if row["item_identifier"].to_s.strip.present?
      unless item
        item = Item.find_by(id: row["item_id"].to_s.strip) if row["item_id"].to_s.strip.present?
      end

      manifestation_identifier = row["manifestation_identifier"].to_s.strip
      manifestation = Manifestation.find_by(manifestation_identifier: manifestation_identifier)
      manifestation ||= Manifestation.find_by(id: row["manifestation_id"].to_s.strip)

      if item && manifestation
        item.manifestation = manifestation
        item.save!
      end

      import_result = ResourceImportResult.create!(resource_import_file_id: id, body: row.fields.join("\t"))
      import_result.item = item
      import_result.manifestation = manifestation
      import_result.save!
      row_num += 1
    end
    transition_to!(:completed)
    mailer = ResourceImportMailer.completed(self)
    send_message(mailer)
  rescue StandardError => e
    self.error_message = "line #{row_num}: #{e.message}"
    save
    transition_to!(:failed)
    mailer = ResourceImportMailer.failed(self)
    send_message(mailer)
    raise e
  end

  private

  def open_import_file(tempfile)
    file = CSV.open(tempfile, col_sep: "\t")
    header_columns = %w[
      original_title manifestation_identifier item_identifier shelf note
      title_transcription title_alternative title_alternative_transcription
      serial manifestation_id publication_place carrier_type
      series_statement_identifier series_original_title series_creator_string
      series_title_transcription series_volume_number_string
      series_title_subseries series_title_subseries_transcription
      creator creator_transcription publisher
      publisher_transcription pub_date date_of_publication year_of_publication
      creator creator_transcription
      contributor contributor_transcription abstract description access_address
      volume_number volume_number_string issue_number issue_number_string
      edition edition_string serial_number isbn issn manifestation_price
      width height depth number_of_pages jpno lccn budget_type bookstore
      language fulltext_content manifestation_required_role doi content_type
      frequency extent start_page end_page dimensions manifestation_memo
      ncid
      ndl_bib_id
      statement_of_responsibility acquired_at call_number circulation_status
      binding_item_identifier binding_call_number binded_at item_price
      use_restriction include_supplements item_note item_url item_memo
      item_required_role
      dummy
    ]
    header_columns += ManifestationCustomProperty.order(:position).pluck(:name).map { |c| "manifestation:#{c}" }
    header_columns += ItemCustomProperty.order(:position).pluck(:name).map { |c| "item:#{c}" }

    if defined?(EnjuSubject)
      header_columns += ClassificationType.order(:position).pluck(:name).map { |c| "classification:#{c}" }
      header_columns += SubjectHeadingType.order(:position).pluck(:name).map { |s| "subject:#{s}" }
    end
    header = file.first
    ignored_columns = header - header_columns
    unless ignored_columns.empty?
      self.error_message = I18n.t("import.following_column_were_ignored", column: ignored_columns.join(", "))
      save!
    end
    rows = CSV.open(tempfile, headers: header, col_sep: "\t")
    # ResourceImportResult.create!(resource_import_file_id: id, body: header.join("\t"))
    tempfile.close(true)
    file.close
    rows
  end

  def import_subject(row)
    subjects = []
    SubjectHeadingType.order(:position).pluck(:name).map { |s| "subject:#{s}" }.each do |column_name|
      type = column_name.split(":").last
      subject_list = row[column_name].to_s.split("//")
      subject_list.map { |value|
        subject_heading_type = SubjectHeadingType.find_by(name: type)
        next unless subject_heading_type

        subject = Subject.new(term: value)
        subject.subject_heading_type = subject_heading_type
        # TODO: Subject typeの設定
        subject.subject_type = SubjectType.find_by(name: "concept")
        subject.save!
        subjects << subject
      }
    end
    subjects
  end

  def import_classification(row)
    classifications = []
    ClassificationType.order(:position).pluck(:name).map { |c| "classification:#{c}" }.each do |column_name|
      type = column_name.split(":").last
      classification_list = row[column_name].to_s.split("//")
      classification_list.map { |value|
        classification_type = ClassificationType.find_by(name: type)
        next unless classification_type

        classification = Classification.new(category: value)
        classification.classification_type = classification_type
        classification.save!
        classifications << classification
      }
    end
    classifications
  end

  def create_item(row, manifestation)
    shelf = Shelf.find_by(name: row["shelf"].to_s.strip)
    shelf ||= default_shelf || Shelf.web
    bookstore = Bookstore.find_by(name: row["bookstore"].to_s.strip)
    budget_type = BudgetType.find_by(name: row["budget_type"].to_s.strip)
    acquired_at = Time.zone.parse(row["acquired_at"]) rescue nil
    binded_at = Time.zone.parse(row["binded_at"]) rescue nil
    item = Item.new(
      manifestation_id: manifestation.id,
      item_identifier: row["item_identifier"],
      price: row["item_price"],
      call_number: row["call_number"].to_s.strip,
      acquired_at: acquired_at,
      binding_item_identifier: row["binding_item_identifier"],
      binding_call_number: row["binding_call_number"],
      binded_at: binded_at,
      url: row["item_url"],
      note: row["item_note"].try(:gsub, /\\n/, "\n"),
      memo: row["item_memo"].try(:gsub, /\\n/, "\n")
    )
    manifestation.items << item
    if defined?(EnjuCirculation)
      circulation_status = CirculationStatus.find_by(name: row["circulation_status"].to_s.strip) || CirculationStatus.find_by(name: "In Process")
      item.circulation_status = circulation_status
      use_restriction = UseRestriction.find_by(name: row["use_restriction"].to_s.strip)
      use_restriction ||= UseRestriction.find_by(name: "Not For Loan")
      item.use_restriction = use_restriction
    end
    item.bookstore = bookstore
    item.budget_type = budget_type
    item.shelf = shelf
    item.shelf = Shelf.web unless item.shelf

    if %w[t true].include?(row["include_supplements"].to_s.downcase.strip)
      item.include_supplements = true
    end
    item.save!
    item
  end

  def update_item(item, row)
    shelf = Shelf.find_by(name: row["shelf"].to_s.strip)
    bookstore = Bookstore.find_by(name: row["bookstore"])
    required_role = Role.find_by(name: row["item_required_role"])

    item.shelf = shelf if shelf
    item.bookstore = bookstore if bookstore
    item.required_role = required_role if required_role

    acquired_at = Time.zone.parse(row["acquired_at"]) rescue nil
    binded_at = Time.zone.parse(row["binded_at"]) rescue nil
    item.acquired_at = acquired_at if acquired_at
    item.binded_at = binded_at if binded_at

    if defined?(EnjuCirculation)
      circulation_status = CirculationStatus.find_by(name: row["circulation_status"])
      checkout_type = CheckoutType.find_by(name: row["checkout_type"])
      use_restriction = UseRestriction.find_by(name: row["use_restriction"].to_s.strip)
      item.circulation_status = circulation_status if circulation_status
      item.checkout_type = checkout_type if checkout_type
      item.use_restriction = use_restriction if use_restriction
    end

    item_columns = %w[
      call_number
      binding_item_identifier binding_call_number binded_at
    ]
    item_columns.each do |column|
      if row[column].present?
        item.assign_attributes(:"#{column}" => row[column])
      end
    end

    item.price = row["item_price"] if row["item_price"].present?
    item.note = row["item_note"].try(:gsub, /\\n/, "\n") if row["item_note"].present?
    item.memo = row["item_memo"].try(:gsub, /\\n/, "\n") if row["item_memo"].present?
    item.url = row["item_url"] if row["item_url"].present?

    if row["include_supplements"]
      if %w[t true].include?(row["include_supplements"].downcase.strip)
        item.include_supplements = true
      elsif item.include_supplements
        item.include_supplements = false
      end
    end

    item
  end

  def fetch(row, options = { edit_mode: "create" })
    manifestation = nil
    item = nil

    if options[:edit_mode] == "update"
      if row["item_identifier"].to_s.strip.present?
        item = Item.find_by(item_identifier: row["item_identifier"].to_s.strip)
      end
      if row["item_id"].to_s.strip.present?
        item = Item.find_by(id: row["item_id"].to_s.strip)
      end

      manifestation = item.manifestation if item

      unless manifestation
        manifestation_identifier = row["manifestation_identifier"].to_s.strip
        manifestation = Manifestation.find_by(manifestation_identifier: manifestation_identifier) if manifestation_identifier
        manifestation ||= Manifestation.find_by(id: row["manifestation_id"])
      end
    end

    title = {}
    title[:original_title] = row["original_title"].to_s.strip
    title[:title_transcription] = row["title_transcription"].to_s.strip
    title[:title_alternative] = row["title_alternative"].to_s.strip
    title[:title_alternative_transcription] = row["title_alternative_transcription"].to_s.strip
    if options[:edit_mode] == "update"
      title[:original_title] = manifestation.original_title if row["original_title"].to_s.strip.blank?
      title[:title_transcription] = manifestation.title_transcription if row["title_transcription"].to_s.strip.blank?
      title[:title_alternative] = manifestation.title_alternative if row["title_alternative"].to_s.strip.blank?
      title[:title_alternative_transcription] = manifestation.title_alternative_transcription if row["title_alternative_transcription"].to_s.strip.blank?
    end
    # title[:title_transcription_alternative] = row['title_transcription_alternative']
    if title[:original_title].blank? && options[:edit_mode] == "create"
      return nil
    end

    # TODO: 小数点以下の表現
    language = Language.find_by(name: row["language"].to_s.strip.camelize) || Language.find_by(iso_639_2: row["language"].to_s.strip.downcase) || Language.find_by(iso_639_1: row["language"].to_s.strip.downcase)

    carrier_type = CarrierType.find_by(name: row["carrier_type"].to_s.strip)
    content_type = ContentType.find_by(name: row["content_type"].to_s.strip)
    frequency = Frequency.find_by(name: row["frequency"].to_s.strip)

    fulltext_content = serial = nil
    if %w[t true].include?(row["fulltext_content"].to_s.downcase.strip)
      fulltext_content = true
    end

    if %w[t true].include?(row["serial"].to_s.downcase.strip)
      serial = true
    end

    creators = row["creator"].to_s.split("//")
    creator_transcriptions = row["creator_transcription"].to_s.split("//")
    creators_list = creators.zip(creator_transcriptions).map { |f, t| { full_name: f.to_s.strip, full_name_transcription: t.to_s.strip } }
    contributors = row["contributor"].to_s.split("//")
    contributor_transcriptions = row["contributor_transcription"].to_s.split("//")
    contributors_list = contributors.zip(contributor_transcriptions).map { |f, t| { full_name: f.to_s.strip, full_name_transcription: t.to_s.strip } }
    publishers = row["publisher"].to_s.split("//")
    publisher_transcriptions = row["publisher_transcription"].to_s.split("//")
    publishers_list = publishers.zip(publisher_transcriptions).map { |f, t| { full_name: f.to_s.strip, full_name_transcription: t.to_s.strip } }
    ResourceImportFile.transaction do
      creator_agents = Agent.import_agents(creators_list)
      contributor_agents = Agent.import_agents(contributors_list)
      publisher_agents = Agent.import_agents(publishers_list)
      subjects = import_subject(row) if defined?(EnjuSubject)
      case options[:edit_mode]
      when "create"
        work = self.class.import_work(title, creator_agents, options)
        if defined?(EnjuSubject)
          work.subjects = subjects.uniq unless subjects.empty?
        end
        expression = self.class.import_expression(work, contributor_agents)
      when "update"
        expression = manifestation
        work = expression
        work.creators = creator_agents.uniq unless creator_agents.empty?
        expression.contributors = contributor_agents.uniq unless contributor_agents.empty?
        if defined?(EnjuSubject)
          work.subjects = subjects.uniq unless subjects.empty?
        end
      end

      attributes = {
        original_title: title[:original_title],
        title_transcription: title[:title_transcription],
        title_alternative: title[:title_alternative],
        title_alternative_transcription: title[:title_alternative_transcription],
        pub_date: row["pub_date"],
        date_of_publication: row["date_of_publication"],
        year_of_publication: row["year_of_publication"],
        volume_number: row["volume_number"],
        volume_number_string: row["volume_number_string"],
        issue_number: row["issue_number"],
        issue_number_string: row["issue_number_string"],
        serial_number: row["serial_number"],
        edition: row["edition"],
        edition_string: row["edition_string"],
        width: row["width"],
        depth: row["depth"],
        height: row["height"],
        price: row["manifestation_price"],
        abstract: row["abstract"].try(:gsub, /\\n/, "\n"),
        description: row["description"].try(:gsub, /\\n/, "\n"),
        # :description_transcription => row['description_transcription'],
        note: row["note"].try(:gsub, /\\n/, "\n"),
        memo: row["manifestation_memo"].try(:gsub, /\\n/, "\n"),
        statement_of_responsibility: row["statement_of_responsibility"],
        access_address: row["access_address"],
        manifestation_identifier: row["manifestation_identifier"],
        publication_place: row["publication_place"],
        extent: row["extent"],
        dimensions: row["dimensions"],
        start_page: row["start_page"],
        end_page: row["end_page"],
      }.delete_if { |_key, value| value.nil? }

      manifestation = self.class.import_manifestation(expression, publisher_agents, attributes,
      {
        edit_mode: options[:edit_mode]
      })

      required_role = Role.find_by(name: row["manifestation_required_role"].to_s.strip.camelize)
      if required_role && row["manifestation_required_role"].present?
        manifestation.required_role = required_role
      else
        manifestation.required_role = Role.find_by(name: "Guest") unless manifestation.required_role
      end

      if language && row["language"].present?
        manifestation.language = language
      else
        manifestation.language = Language.find_by(name: "unknown") unless manifestation.language
      end

      manifestation.carrier_type = carrier_type if carrier_type
      manifestation.manifestation_content_type = content_type if content_type
      manifestation.frequency = frequency if frequency
      # manifestation.start_page = row[:start_page].to_i if row[:start_page]
      # manifestation.end_page = row[:end_page].to_i if row[:end_page]
      manifestation.serial = serial if row["serial"]
      manifestation.fulltext_content = fulltext_content if row["fulltext_content"]

      if row["series_original_title"].to_s.strip.present?
        Manifestation.transaction do
          if manifestation.series_statements.exists?
            manifestation.series_statements.delete_all
          end
          if row["series_original_title"]
            series_statement = SeriesStatement.new(
              original_title: row["series_original_title"],
              title_transcription: row["series_title_transcription"],
              title_subseries: row["series_title_subseries"],
              title_subseries_transcription: row["series_title_subseries_transcription"],
              volume_number_string: row["series_volume_number_string"],
              creator_string: row["series_creator_string"]
            )
            series_statement.manifestation = manifestation
            series_statement.save!
          end
        end
      end

      manifestation.doi_record = set_doi(row)
      manifestation.create_jpno_record(body: row["jpno"]) if row["jpno"].present?
      manifestation.create_ncid_record(body: row["ncid"]) if row["ncid"].present?
      if row["isbn"].present?
        row["isbn"].to_s.split("//").each do |isbn|
          lisbn = Lisbn.new(isbn)
          manifestation.isbn_records.find_or_create_by(body: lisbn.isbn13) if lisbn.isbn13
        end
      end

      if row["issn"].present?
        row["issn"].to_s.split("//").each do |issn|
          manifestation.issn_records.find_or_create_by(body: issn) if issn.present?
        end
      end

      identifiers = set_identifier(row)

      if manifestation.save
        Manifestation.transaction do
          if options[:edit_mode] == "update"
            unless identifiers.empty?
              identifiers.each do |v|
                v.manifestation = manifestation
                v.save
              end
            end
          else
            manifestation.identifiers << identifiers
          end
        end

        if defined?(EnjuSubject)
          classifications = import_classification(row)
          if classifications.present?
            manifestation.classifications = classifications
          end
        end
      end

      manifestation.save!

      if options[:edit_mode] == "create"
        manifestation.set_agent_role_type(creators_list)
        manifestation.set_agent_role_type(contributors_list, scope: :contributor)
        manifestation.set_agent_role_type(publishers_list, scope: :publisher)
      end
    end

    manifestation
  end

  def set_identifier(row)
    identifiers = []
    %w[isbn issn jpno ncid lccn iss_itemno].each do |id_type|
      next unless row[id_type.to_s].present?

      row[id_type].split(/\/\//).each do |identifier_s|
        import_id = Identifier.new(body: identifier_s)
        identifier_type = IdentifierType.find_or_create_by!(name: id_type)
        import_id.identifier_type = identifier_type
        identifiers << import_id if import_id.valid?
      end
    end

    identifiers
  end

  def set_doi(row)
    return if row["doi"].blank?

    doi = URI.parse(row["doi"].downcase).path.gsub(/^\//, "")
    doi_record = DoiRecord.new(body: doi)

    doi_record
  end

  def self.import_manifestation_custom_value(row, manifestation)
    values = []
    ManifestationCustomProperty.order(:position).pluck(:name).map { |c| "manifestation:#{c}" }.each do |column_name|
      value = nil
      property = column_name.split(":").last
      next if row[column_name].blank?

      if manifestation
        value = manifestation.manifestation_custom_values.find_by(manifestation_custom_property: property)
      end

      if value
        value.value = row[column_name]
      else
        value = ManifestationCustomValue.new(
          manifestation_custom_property: ManifestationCustomProperty.find_by(name: property),
          value: row[column_name]
        )
      end
      values << value
    end
    values
  end

  def self.import_item_custom_value(row, item)
    values = []
    ItemCustomProperty.order(:position).pluck(:name).map { |c| "item:#{c}" }.each do |column_name|
      value = nil
      property = column_name.split(":").last
      next if row[column_name].blank?

      value = item.item_custom_values.find_by(item_custom_property: property) if item

      if value
        value.value = row[column_name]
      else
        value = ItemCustomValue.new(
          item_custom_property: ItemCustomProperty.find_by(name: property),
          value: row[column_name]
        )
      end
      values << value
    end
    values
  end
end

# == Schema Information
#
# Table name: resource_import_files
#
#  id                          :bigint           not null, primary key
#  edit_mode                   :string
#  error_message               :text
#  executed_at                 :datetime
#  note                        :text
#  resource_import_fingerprint :string
#  user_encoding               :string
#  created_at                  :datetime         not null
#  updated_at                  :datetime         not null
#  default_shelf_id            :bigint
#  parent_id                   :bigint
#  user_id                     :bigint           not null
#
# Indexes
#
#  index_resource_import_files_on_parent_id  (parent_id)
#  index_resource_import_files_on_user_id    (user_id)
#
# Foreign Keys
#
#  fk_rails_...  (user_id => users.id)
#
