class Contributions::DonationsController < ApplicationController
  include BtcpayHelper

  before_action :authenticate_user!
  before_action :set_donation_methods, only: [:index, :create]
  before_action :require_donation_method_enabled, only: [:create]
  before_action :validate_donation_params, only: [:create]
  before_action :set_donation, only: [:confirm_btcpay]

  # GET /contributions/donations
  def index
    @current_section = :contributions
    @donations_completed = current_user.donations.completed.order('paid_at desc')
    @donations_pending = current_user.donations.processing.order('created_at desc')

    if Setting.lndhub_enabled?
      begin
        lndhub_authenticate
        lndhub_fetch_balance
      rescue
        @balance = 0
      end
    end
  end

  # POST /contributions/donations
  def create
    if params[:currency] == "sats"
      fiat_amount = nil
      fiat_currency = nil
      amount_sats = params[:amount]
    else
      fiat_amount = params[:amount].to_i
      fiat_currency = params[:currency]
      amount_sats = nil
    end

    @donation = current_user.donations.create!(
      donation_method: params[:donation_method],
      payment_method: nil,
      paid_at: nil,
      amount_sats: amount_sats,
      fiat_amount: (fiat_amount.nil? ? nil : fiat_amount * 100), # store in cents
      fiat_currency: fiat_currency,
      public_name: params[:public_name]
    )

    case params[:donation_method]
    when "btcpay"
      res = BtcpayManager::CreateInvoice.call(
        amount: fiat_amount || (amount_sats.to_f / 100000000),
        currency: fiat_currency || "BTC",
        redirect_url: confirm_btcpay_contributions_donation_url(@donation)
      )

      @donation.update! btcpay_invoice_id: res["id"]

      redirect_to btcpay_checkout_url(res["id"]), allow_other_host: true
    else
      redirect_to contributions_donations_url, flash: {
        error: "Donation method currently not available"
      }
    end
  end

  def confirm_btcpay
    redirect_to contributions_donations_url and return if @donation.completed?

    invoice = BtcpayManager::FetchInvoice.call(invoice_id: @donation.btcpay_invoice_id)

    if @donation.amount_sats.present?
      # TODO make default fiat currency configurable and/or determine from user's
      # i18n browser settings
      @donation.fiat_currency = "EUR"
      exchange_rate = BtcpayManager::FetchExchangeRate.call(fiat_currency: @donation.fiat_currency)
      @donation.fiat_amount = (((@donation.amount_sats.to_f / 100000000) * exchange_rate) * 100).to_i
    else
      amt_str = invoice["paymentMethods"].first["amount"]
      @donation.amount_sats = amt_str.tr(".","").sub(/0*$/, "").to_i
    end

    case invoice["status"]
    when "Settled"
      @donation.paid_at = DateTime.now
      @donation.payment_status = "settled"
      @donation.save!
      flash_message = { success: "Thank you!" }
    when "Processing"
      unless @donation.processing?
        @donation.payment_status = "processing"
        @donation.save!
        flash_message = { success: "Thank you! We will send you an email when the payment is confirmed." }
        BtcpayCheckDonationJob.set(wait: 20.seconds).perform_later(@donation)
      end
    when "Expired"
      flash_message = { warning: "The payment request for this donation has expired" }
    else
      flash_message = { warning: "Could not determine status of payment" }
    end

    redirect_to contributions_donations_url, flash: flash_message
  end

  private

    def set_donation
      @donation = current_user.donations.find_by(id: params[:id])
      http_status :not_found unless @donation.present?
    end

    def set_donation_methods
      @donation_methods = []
      @donation_methods.push :btcpay if Setting.btcpay_enabled?
      @donation_methods.push :lndhub if Setting.lndhub_enabled?
      @donation_methods.push :opencollective if Setting.opencollective_enabled?
    end

    def require_donation_method_enabled
      http_status :forbidden unless @donation_methods.include?(
        params[:donation_method].to_sym
      )
    end

    def validate_donation_params
      if !%w[EUR USD sats].include?(params[:currency]) || (params[:amount].to_i <= 0)
        http_status :unprocessable_entity
      end
    end
end
