# typed: strict
class Tasks::Fa::MigrateFaUserPostFavs < Tasks::InterruptableTask
  extend T::Sig

  sig { override.returns(String) }
  def progress_key
    "fa-migrate-fa-user-post-favs"
  end

  sig { params(user: Domain::User::FaUser, batch_size: Integer).void }
  def run_for_user(user:, batch_size: 100)
    user_faved_post_ids = user.faved_posts.pluck(:id)

    total = user_faved_post_ids.size
    return if total <= 0
    pb = ProgressBar.create(format: Tasks::InterruptableTask::PB_FORMAT, total:)
    pb.progress = 0

    user_faved_post_ids.each_slice(batch_size) do |post_ids|
      post_ids_clause = "domain_posts.id IN (#{post_ids.join(",")})"
      migrate_posts(post_ids_clause)
      pb.progress = [pb.progress + post_ids.size, pb.total].min
      break if interrupted?
    end
  end

  sig { params(start_at: T.nilable(String), batch_size: Integer).void }
  def run_for_posts(start_at: nil, batch_size: 100)
    domain_post_id_range = Domain::Post.maximum(:id)
    start_at_id = (get_progress(start_at) || 0).to_i
    total = domain_post_id_range - start_at_id
    return if total <= 0
    pb = ProgressBar.create(format: Tasks::InterruptableTask::PB_FORMAT, total:)

    (start_at_id..domain_post_id_range)
      .step(batch_size)
      .each do |batch_start|
        batch_end = [batch_start + batch_size, domain_post_id_range].min
        batch_end += 1 if batch_end == domain_post_id_range

        post_ids_clause =
          "domain_posts.id >= #{batch_start} AND domain_posts.id < #{batch_end}"
        migrate_posts(post_ids_clause)

        pb.progress = [pb.progress + batch_size, pb.total].min
        save_progress(batch_end.to_s)
        break if interrupted?
      end
  end

  sig { params(post_ids_clause: String).void }
  def migrate_posts(post_ids_clause)
    ReduxApplicationRecord.transaction do
      ReduxApplicationRecord.connection.execute <<-SQL
        UPDATE domain_user_post_favs
        SET type = 'Domain::UserPostFav::FaUserPostFav'
        WHERE post_id IN (
          SELECT id
          FROM domain_posts
          WHERE type = 'Domain::Post::FaPost'
          AND #{post_ids_clause}
        )
      SQL

      ReduxApplicationRecord.connection.execute <<-SQL
        UPDATE domain_user_post_favs
        SET json_attributes =
            domain_user_post_favs.json_attributes
          || jsonb_build_object('fav_id', domain_fa_fav_id_and_dates.fav_fa_id)
                  || jsonb_build_object('explicit_time', EXTRACT(EPOCH FROM domain_fa_fav_id_and_dates.date)::integer)
        FROM domain_fa_fav_id_and_dates
        JOIN domain_posts ON (domain_posts.json_attributes->>'fa_id')::integer = domain_fa_fav_id_and_dates.post_fa_id
        WHERE domain_user_post_favs.post_id = domain_posts.id
          AND domain_fa_fav_id_and_dates.user_id = domain_user_post_favs.user_id
          AND domain_user_post_favs.type = 'Domain::UserPostFav::FaUserPostFav'
          AND domain_posts.type = 'Domain::Post::FaPost'
          AND #{post_ids_clause}
      SQL
    end
  end
end
