# frozen_string_literal: true

module ImportExport
  class BaseExporter
    attr_reader :export_data, :categories

    CATEGORY_ATTRS = %i[
      id
      name
      color
      created_at
      user_id
      slug
      description
      text_color
      auto_close_hours
      position
      parent_category_id
      auto_close_based_on_last_post
      topic_template
      all_topics_wiki
      permissions_params
    ]

    GROUP_ATTRS = %i[
      id
      name
      created_at
      automatic_membership_email_domains
      primary_group
      title
      grant_trust_level
      incoming_email
      bio_raw
      allow_membership_requests
      full_name
      default_notification_level
      visibility_level
      public_exit
      public_admission
      membership_request_template
      messageable_level
      mentionable_level
      members_visibility_level
      publish_read_state
    ]

    USER_ATTRS = %i[
      id
      email
      username
      name
      created_at
      trust_level
      active
      last_emailed_at
      custom_fields
    ]

    TOPIC_ATTRS = %i[id title created_at views category_id closed archived archetype]

    POST_ATTRS = %i[
      id
      user_id
      post_number
      raw
      created_at
      reply_to_post_number
      hidden
      hidden_reason_id
      wiki
    ]

    def categories
      @categories ||= Category.all.to_a
    end

    def export_categories
      data = []

      categories.each do |cat|
        data << CATEGORY_ATTRS.inject({}) do |h, a|
          h[a] = cat.public_send(a)
          h
        end
      end

      data
    end

    def export_categories!
      @export_data[:categories] = export_categories

      self
    end

    def export_groups(group_names)
      data = []
      groups = Group.all
      groups = groups.where(name: group_names) if group_names.present?

      groups.find_each do |group|
        attrs =
          GROUP_ATTRS.inject({}) do |h, a|
            h[a] = group.public_send(a)
            h
          end
        attrs[:user_ids] = group.users.pluck(:id)
        data << attrs
      end

      data
    end

    def export_groups!
      @export_data[:groups] = export_groups([])

      self
    end

    def export_category_groups
      groups = []
      group_names = []
      auto_group_names = Group::AUTO_GROUPS.keys.map(&:to_s)

      @export_data[:categories].each do |c|
        c[:permissions_params].each do |group_name, _|
          group_names << group_name unless auto_group_names.include?(group_name.to_s)
        end
      end

      group_names.uniq!
      return [] if group_names.empty?

      export_groups(group_names)
    end

    def export_category_groups!
      @export_data[:groups] = export_category_groups

      self
    end

    def export_group_users
      user_ids = []

      @export_data[:groups].each { |g| user_ids += g[:user_ids] }

      user_ids.uniq!
      return User.none if user_ids.empty?

      users = User.where(id: user_ids)
      export_users(users)
    end

    def export_group_users!
      @export_data[:users] = export_group_users

      self
    end

    def export_topics
      data = []

      @topics.each do |topic|
        puts topic.title

        topic_data =
          TOPIC_ATTRS.inject({}) do |h, a|
            h[a] = topic.public_send(a)
            h
          end

        topic_data[:posts] = []

        topic.ordered_posts.find_each do |post|
          attributes =
            POST_ATTRS.inject({}) do |h, a|
              h[a] = post.public_send(a)
              h
            end

          attributes[:raw] = attributes[:raw].gsub(
            'src="/uploads',
            "src=\"#{Discourse.base_url_no_prefix}/uploads",
          )

          topic_data[:posts] << attributes
        end

        data << topic_data
      end

      data
    end

    def export_topics!
      @export_data[:topics] = export_topics

      self
    end

    def export_topic_users
      return if @export_data[:topics].blank?
      topic_ids = @export_data[:topics].pluck(:id)

      users = User.joins(:posts).where("posts.topic_id IN (?)", topic_ids).distinct

      export_users(users)
    end

    def export_topic_users!
      @export_data[:users] = export_topic_users

      self
    end

    def export_users(users)
      data = []

      users.find_each do |u|
        next if u.id == Discourse::SYSTEM_USER_ID

        x =
          USER_ATTRS.inject({}) do |h, a|
            h[a] = u.public_send(a)
            h
          end

        x.merge(
          bio_raw: u.user_profile.bio_raw,
          website: u.user_profile.website,
          location: u.user_profile.location,
        )
        data << x
      end

      data
    end

    def export_translation_overrides
      @export_data[:translation_overrides] = TranslationOverride.all.select(
        :locale,
        :translation_key,
        :value,
      )

      self
    end

    def default_filename_prefix
      raise "Overwrite me!"
    end

    def save_to_file(filename = nil)
      output_basename =
        filename ||
          File.join("#{default_filename_prefix}-#{Time.now.strftime("%Y-%m-%d-%H%M%S")}.json")
      File.open(output_basename, "w:UTF-8") { |f| f.write(@export_data.to_json) }
      puts "Export saved to #{output_basename}"
      output_basename
    end
  end
end