# typed: ignore

class CreateUpholdChannelCardJob < ApplicationJob
  sidekiq_options queue: :default

  def perform(uphold_connection_id, channel_id)
    uphold_connection = UpholdConnection.find(uphold_connection_id)
    channel = Channel.find(channel_id)
    return unless uphold_connection&.is_member? &&
      uphold_connection.uphold_verified? &&
      uphold_connection&.status == "ok" &&
      uphold_connection.valid_country? &&
      channel&.verified? &&
      uphold_connection&.publisher&.active?

    unless uphold_connection.can_create_uphold_cards?
      Rails.logger.info("Could not create uphold card for channel #{uphold_connection.publisher_id}. Uphold Verified: #{uphold_connection.uphold_verified}")
      return
    end

    upfc = UpholdConnectionForChannel.where(
      uphold_connection: uphold_connection,
      currency: uphold_connection.default_currency,
      channel_identifier: channel.details.channel_identifier
    ).first_or_create(channel_id: channel_id)

    # Make sure the connection is active before hitting the API
    # refresh_authorization should not hit the uphold API if it has active credentials and
    # it should block the uphold connection from making concurrent refresh requests
    uphold_connection.refresh_authorization!
    card_id = find_or_create_card(uphold_connection, channel, upfc)

    LogException.perform("Failed to create Uphold Channel Card", expected: true)
    return unless card_id.present?

    # If the channel was deleted and then recreated we should update this to be the new channel id
    upfc.update(
      address: get_address(uphold_connection, card_id),
      card_id: card_id,
      # It's possible a channel can be removed, so this covers re-linking an existing UCFC to the re-added channel.
      channel_id: channel_id,
      uphold_id: uphold_connection.uphold_id
    )
  end

  def find_or_create_card(uphold_connection, channel, upfc)
    # In the past if a user disconnects and reconnects to a different uphold account then the connection for the channel might have an out of date card address
    return upfc.card_id if card_exists?(uphold_connection, upfc.card_id)

    # If a user transfers their channel then we should try not to create duplicate uphold cards
    card_label = "#{channel.type_display} - #{channel.details.publication_title} - Brave Creators"
    cards = UpholdClient.card.where(uphold_connection: uphold_connection)

    return if cards.nil?

    card_id = cards.detect { |c| c.label.eql?(card_label) }&.id

    if card_id.blank?
      # If the card doesn't exist so we should create it
      card_id = UpholdClient.card.create(
        uphold_connection: uphold_connection,
        currency: uphold_connection.default_currency,
        label: card_label
      ).id
    end

    channel.update_site_banner_lookup!

    card_id
  end

  def card_exists?(uphold_connection, card_id)
    return false if card_id.blank?

    UpholdClient.card.find(uphold_connection: uphold_connection, id: card_id).present?
  rescue Faraday::ResourceNotFound
    false
  end

  def get_address(uphold_connection, card_id)
    address = addresses(uphold_connection, card_id).detect { |a| a.type == UpholdConnectionForChannel::NETWORK }
    address = address.formats.first.dig("value") if address.present?

    return address if address.present?

    UpholdClient.address.create(
      uphold_connection: uphold_connection,
      id: card_id,
      network: UpholdConnectionForChannel::NETWORK
    )
  end

  def addresses(uphold_connection, card_id)
    UpholdClient.address.all(
      uphold_connection: uphold_connection,
      id: card_id
    )
  rescue Faraday::ResourceNotFound
    []
  end
end
