# typed: strict
class Domain::Inkbunny::Job::UserGalleryJob < Domain::Inkbunny::Job::Base
  ApiSearchPageProcessor = Domain::Inkbunny::Job::ApiSearchPageProcessor

  sig { override.params(args: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
  def perform(args)
    user = user_from_args!
    logger.push_tags(
      make_tag("id", user.id),
      make_tag("user_ib_id", user.ib_id),
    )

    if user.scanned_gallery_at&.after?(1.week.ago)
      logger.warn(
        "gallery scanned #{time_ago_in_words(user.scanned_gallery_at)}, skipping",
      )
      return
    end

    processor = ApiSearchPageProcessor.new
    rid = T.let(nil, T.nilable(String))
    page = T.let(1, Integer)
    loop_count = T.let(0, Integer)
    max_loop_count = T.let(2000, Integer)

    loop do
      loop_count += 1
      raise("loop_count: #{loop_count}") if loop_count > max_loop_count

      url =
        ApiSearchPageProcessor.build_api_search_url(
          ib_user_id: user.ib_id,
          rid: rid,
          page: page,
        )

      response = http_client.post(url)
      if response.status_code != 200
        fatal_error("api_search failed: #{response.status_code}")
      end
      result =
        processor.process!(
          JSON.parse(response.body),
          caused_by_entry: response.log_entry,
        )
      num_new_posts = result[:num_new_posts]
      logger.info(
        [
          "[rid: #{rid}]",
          "[page: #{page}]",
          "[new posts: #{num_new_posts}]",
          "[total new posts: #{result[:num_total_new_posts]}]",
          "[total changed posts: #{result[:num_total_changed_posts]}]",
          "[total posts: #{result[:num_total_posts]}]",
        ].join(" "),
      )

      user.reload
      if user.scanned_gallery_at.present? && num_new_posts == 0
        logger.info("[no new posts, stopping]")
        break
      end
      rid = T.cast(result[:rid], String)
      break if T.cast(result[:num_pages], Integer) <= page
      page += 1
    end

    user.scanned_gallery_at = Time.current
    user.save!

    if processor.changed_posts.any?
      defer_job(
        Domain::Inkbunny::Job::UpdatePostsJob,
        { ib_post_ids: processor.changed_posts.map(&:ib_id) },
      )
    end

    Domain::User.reset_counters(user.id, :user_post_creations)
  ensure
    logger.pop_tags
  end
end
