namespace :wiki do
  desc 'Wiki 移行'
  task migrate: :environment do
    require 'digest'
    require 'gollum-lib'

    wiki = Gollum::Wiki.new(Rails.root.join('wiki').to_s)

    WikiPage.where.missing(:wiki_revisions).find_each do |wiki_page|
      page = wiki.page("#{ wiki_page.id }.md")
      next unless page

      versions = page.versions
      next if versions.blank?

      base_revision_id = nil
      versions.reverse_each do |version|
        pg = wiki.page("#{ wiki_page.id }.md", version.id)
        raw = pg&.raw_data
        next unless raw

        lines = raw.force_encoding('UTF-8').split("\n")

        line_shas = lines.map { |l| Digest::SHA256.hexdigest(l) }
        tree_sha = Digest::SHA256.hexdigest(line_shas.join(','))

        at = version.authored_date

        line_id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h

        missing_rows = []
        line_shas.each_with_index do |sha, i|
          next if line_id_by_sha.key?(sha)

          missing_rows << { sha256:     sha,
                            body:       lines[i],
                            created_at: at,
                            updated_at: at }
        end

        if missing_rows.any?
          WikiLine.upsert_all(missing_rows)
          line_id_by_sha = WikiLine.where(sha256: line_shas).pluck(:sha256, :id).to_h
        end
        line_ids = line_shas.map { |sha| line_id_by_sha.fetch(sha) }

        rev = nil
        ActiveRecord::Base.transaction do
          wiki_page.lock!

          rev = WikiRevision.create!(
              wiki_page:,
              base_revision_id:,
              created_user_id:  (Integer(version.author.name) rescue 2),
              kind:             :content,
              redirect_page_id: nil,
              message:          nil,
              lines_count:      lines.length,
              tree_sha256:      tree_sha,
              created_at:       at,
              updated_at:       at)

          rows = line_ids.each_with_index.map do |line_id, pos|
            { wiki_revision_id: rev.id,
              wiki_line_id:     line_id,
              position:         pos }
          end
          WikiRevisionLine.insert_all!(rows)
        end
        base_revision_id = rev.id
      end
    end
  end
end
