# License: AGPL-3.0-or-later WITH Web-Template-Output-Additional-Permission-3.0-or-later
module QueueDonations
  def self.execute_for_donation(id)
    donation = Donation.find(id)
    return unless donation

    execute([donation])
  end

  def self.execute_all
    donations = fetch_donations
    return if donations.empty?
    donations_ids = donations.collect(&:id)

    execute(donations)
  end

  def self.dry_execute_all
puts "dry push donations to civi"
    donations = fetch_donations
    return if donations.empty?
    donations_ids = donations.collect(&:id)

    dry_execute(donations)
  end

  private

  def self.execute(donations)
    push(donations)

    donations_ids = donations.collect(&:id)
    set_queued_for_import_at(donations_ids)

  rescue Bunny::Exception, Bunny::ClientTimeout, Bunny::ConnectionTimeout
    Rails.logger.warn "Bunny error: QueueDonations.execute failed for ids #{donations_ids}"
    return
  end

  def self.dry_execute(donations)
    push(donations)

  rescue Bunny::Exception, Bunny::ClientTimeout, Bunny::ConnectionTimeout
    Rails.logger.warn "Bunny error: QueueDonations.dry_execute failed for ids #{donations_ids}"
    return
  end

  def self.push(donations)
    connection = Bunny.new(
      host: Settings.integration.host,
      vhost: Settings.integration.vhost,
      user: Settings.integration.user,
      password: Settings.integration.password
    )
    connection.start
    channel = connection.create_channel
    exchange = channel.topic(Settings.integration.exchange, durable: true)

    donations.each do |donation|
      exchange.publish(
        prepare_donation_params(donation).to_json,
        routing_key: Settings.integration.routing_key
      )
    end

    connection.close
  end

  def self.set_queued_for_import_at(ids)
    timestamp = Time.current
    Qx.update(:donations).
      where('id IN ($ids)', ids: ids).
      set(queued_for_import_at: timestamp).
      execute
  end

  def self.fetch_donations
    Donation.
      where('queued_for_import_at IS null').
      includes(:supporter, :nonprofit, :tracking, :payment,:recurring_donation)
  end

  def self.prepare_donation_params(donation)
    nonprofit = donation.nonprofit
    tracking = donation.tracking
    campaign = donation.campaign
    recurring = donation.recurring_donation

    action_type = :donate
    action_technical_type = "cc.wemove.eu:donate"
    action_name = "undefined_#{donation.supporter.locale}"
    external_id = campaign ? campaign.external_identifier : "cc_default_#{nonprofit.id}"

    data = {
      action_type: action_type,
      action_technical_type: action_technical_type,
      create_dt: donation.created_at,
      action_name: action_name || "slug-#{campaign.id}-#{donation.supporter.locale}",
      external_id: external_id || "cc_#{campaign.id}",
      contact: {},
      donation: {}
    }

    data[:contact] = supporter_data(donation.supporter)
    data[:donation] = donation_data(donation)
    data[:source] = tracking_data(donation.tracking) if donation.tracking
    data[:recurring] = recurring_data(donation.recurring_donation) if donation.recurring_donation

    data
  end

  def self.supporter_data(supporter)
    {
      language: supporter.locale,
      firstname: supporter.first_name,
      lastname: supporter.last_name,
      emails: [
        { email: supporter.email }
      ],
      addresses: [
        { zip: supporter.zip_code, country: supporter.country }],
    }
  end

  def self.donation_data(donation)
    common_data = {
      amount: donation.amount / 100.0,
      currency: donation.nonprofit.currency,
      recurring_id: donation.recurring_donation ? "cc_#{donation.recurring_donation.id}" : nil,
      external_identifier: "cc_#{donation.id}",
      type: donation.recurring ? "recurring" : "single"
    }

    if donation.card_id
      data = common_data.merge({
        payment_processor: "stripe",
        amount_charged: donation.payment.charge.amount / 100.0,
        transaction_id: donation.payment.charge.stripe_charge_id,
        status: donation.payment.charge.paid? ? "success" : "not_paid"
      })
    elsif donation.direct_debit_detail_id
      data = common_data.merge({
        payment_processor: "sepa",
        amount_charged: 0,
        transaction_id: "cc_#{donation.id}",
        iban: donation.direct_debit_detail.iban,
        bic: donation.direct_debit_detail.bic,
        account_holder: donation.direct_debit_detail.account_holder_name,
        status: "success"
      })
    end

    data
  end

  def self.recurring_data(recurring)
    {
      id: recurring.id,
      start: recurring.start_date,
      time_unit: recurring.time_unit,
      active: recurring.active,
    }
  end
  def self.tracking_data(tracking)
    {
      source: tracking.utm_source,
      medium: tracking.utm_medium,
      campaign: tracking.utm_campaign,
      content: tracking.utm_content
    }
  end
end