# typed: strict
class Domain::Sofurry::Job::ScanUserJob < Domain::Sofurry::Job::Base
  self.default_priority = -30

  sig { override.params(args: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
  def perform(args)
    user = user_from_args!
    logger.push_tags(make_arg_tag(user))
    logger.info(format_tags(make_arg_tag(user.page_scan, name: "page_scan")))
    user = scan_user_profile(user) if force_scan? || user.page_scan.due?

    if user.avatar.nil? && (sfid = user.sofurry_id)
      avatar =
        user.create_avatar!(
          url_str: "https://www.sofurry.com/std/avatar?user=#{sfid}",
        )
      defer_job(Domain::Sofurry::Job::UserAvatarJob, { avatar: })
    end
  ensure
    user.save! if user
  end

  private

  sig do
    params(user: Domain::User::SofurryUser).returns(Domain::User::SofurryUser)
  end
  def scan_user_profile(user)
    logger.info("Scanning user page for #{user.username}")
    user_sofurry_id = user.sofurry_id
    user_sofurry_url_name = user.username

    if user_sofurry_id.nil? && user_sofurry_url_name.nil?
      logger.error("user has no sofurry_id or username")
      return user
    end

    url =
      if user_sofurry_id
        "https://api2.sofurry.com/std/getUserProfile?id=#{user_sofurry_id}"
      else
        "https://api2.sofurry.com/std/getUserProfile?username=#{user_sofurry_url_name}"
      end

    response = http_client.get(url)
    if response.status_code != 200
      logger.error("failed to get user profile: #{response.status_code}")
      return user
    end

    user.last_scan_log_entry = response.log_entry

    user_profile_json = JSON.parse(response.body)
    if user_profile_json["error"]
      if user_profile_json["errormessage"] == "User not found"
        logger.error(format_tags("user not found"))
        user.scanned_page_at = Time.now
        user.state_error!
        return user
      else
        user.state_error!
        fatal_error(
          format_tags(make_tag("error", user_profile_json["errormessage"])),
        )
      end
    end

    json_sofurry_id = user_profile_json["userID"]&.to_i
    if user_sofurry_id.present? && user_sofurry_id != json_sofurry_id
      fatal_error(
        "sofurry_id mismatch: #{user_sofurry_id} != #{json_sofurry_id}",
      )
    end

    if user_sofurry_id.nil? && user.new_record?
      by_sofurry_id =
        Domain::User::SofurryUser.find_by(sofurry_id: json_sofurry_id)
      user = by_sofurry_id if by_sofurry_id.present?
    end

    user.sofurry_id ||= json_sofurry_id
    registered_at = user_profile_json["registrationDate"]
    if registered_at == "long long ago"
      user.registered_at = Time.at(0)
    else
      user.registered_at = Time.parse(registered_at)
    end

    user.profile_description = user_profile_json["description"]
    user.profile_species = user_profile_json["species"]
    user.profile_gender = user_profile_json["gender"]&.to_i
    user.profile_orientation = user_profile_json["orientation"]&.to_i
    user.profile_mateship_status = user_profile_json["mateshipStatus"]&.to_i
    user.profile_country = user_profile_json["country"]
    user.profile_city = user_profile_json["city"]
    user.profile_num_submissions =
      user_profile_json["submissionCount"]&.to_i || 0
    user.profile_num_submission_views =
      user_profile_json["submissionViewCount"]&.to_i || 0
    user.profile_num_comments_received =
      user_profile_json["commentCount"]&.to_i || 0
    user.profile_num_comments_posted =
      user_profile_json["commentPostedCount"]&.to_i || 0
    user.profile_num_profile_views =
      user_profile_json["profileViewCount"]&.to_i || 0
    user.scanned_page_at = Time.now
    user.state_ok!
    user.save!

    user
  end
end
