module ShopifyApp::EnsureBilling

def billing_required?

def billing_required?
  ShopifyApp.configuration.requires_billing?
end

def check_billing(session = current_shopify_session)

def check_billing(session = current_shopify_session)
  return true if session.blank? || !billing_required?
  confirmation_url = nil
  if has_active_payment?(session)
    has_payment = true
  else
    has_payment = false
    confirmation_url = request_payment(session)
  end
  unless has_payment
    if request.xhr?
      add_top_level_redirection_headers(url: confirmation_url, ignore_response_code: true)
      ShopifyApp::Logger.debug("Responding with 401 unauthorized")
      head(:unauthorized)
    elsif ShopifyApp.configuration.embedded_app?
      fullpage_redirect_to(confirmation_url)
    else
      redirect_to(confirmation_url, allow_other_host: true)
    end
  end
  has_payment
end

def handle_billing_error(error)

def handle_billing_error(error)
  logger.info("#{error.message}: #{error.errors}")
  redirect_to_login
end

def has_active_payment?(session)

def has_active_payment?(session)
  if recurring?
    has_subscription?(session)
  else
    has_one_time_payment?(session)
  end
end

def has_one_time_payment?(session)

def has_one_time_payment?(session)
  ShopifyApp::Logger.debug("Checking if has one time payment")
  purchases = nil
  end_cursor = nil
  loop do
    response = run_query(session: session, query: ONE_TIME_PURCHASES_QUERY, variables: { endCursor: end_cursor })
    purchases = response.body["data"]["currentAppInstallation"]["oneTimePurchases"]
    purchases["edges"].each do |purchase|
      node = purchase["node"]
      if node["name"] == ShopifyApp.configuration.billing.charge_name &&
          (!Rails.env.production? || !node["test"]) &&
          node["status"] == "ACTIVE"
        return true
      end
    end
    end_cursor = purchases["pageInfo"]["endCursor"]
    break unless purchases["pageInfo"]["hasNextPage"]
  end
  false
end

def has_subscription?(session)

def has_subscription?(session)
  ShopifyApp::Logger.debug("Checking if shop has subscription")
  response = run_query(session: session, query: RECURRING_PURCHASES_QUERY)
  subscriptions = response.body["data"]["currentAppInstallation"]["activeSubscriptions"]
  subscriptions.each do |subscription|
    if subscription["name"] == ShopifyApp.configuration.billing.charge_name &&
        (!Rails.env.production? || !subscription["test"])
      return true
    end
  end
  false
end

def recurring?

def recurring?
  RECURRING_INTERVALS.include?(ShopifyApp.configuration.billing.interval)
end

def request_one_time_payment(session:, return_url:)

def request_one_time_payment(session:, return_url:)
  response = run_query(
    session: session,
    query: ONE_TIME_PURCHASE_MUTATION,
    variables: {
      name: ShopifyApp.configuration.billing.charge_name,
      price: {
        amount: ShopifyApp.configuration.billing.amount,
        currencyCode: ShopifyApp.configuration.billing.currency_code,
      },
      returnUrl: return_url,
      test: ShopifyApp.configuration.billing.test,
    },
  )
  response.body
end

def request_payment(session)

def request_payment(session)
  shop = session.shop
  host = Base64.encode64("#{shop}/admin")
  return_url = "#{ShopifyAPI::Context.host}?shop=#{shop}&host=#{host}"
  if recurring?
    data = request_recurring_payment(session: session, return_url: return_url)
    data = data["data"]["appSubscriptionCreate"]
  else
    data = request_one_time_payment(session: session, return_url: return_url)
    data = data["data"]["appPurchaseOneTimeCreate"]
  end
  raise BillingError.new("Error while billing the store", data["userErrors"]) unless data["userErrors"].empty?
  data["confirmationUrl"]
end

def request_recurring_payment(session:, return_url:)

def request_recurring_payment(session:, return_url:)
  response = run_query(
    session: session,
    query: RECURRING_PURCHASE_MUTATION,
    variables: {
      name: ShopifyApp.configuration.billing.charge_name,
      lineItems: {
        plan: {
          appRecurringPricingDetails: {
            interval: ShopifyApp.configuration.billing.interval,
            price: {
              amount: ShopifyApp.configuration.billing.amount,
              currencyCode: ShopifyApp.configuration.billing.currency_code,
            },
          },
        },
      },
      returnUrl: return_url,
      trialDays: ShopifyApp.configuration.billing.trial_days,
      test: ShopifyApp.configuration.billing.test,
    },
  )
  response.body
end

def run_query(session:, query:, variables: nil)

def run_query(session:, query:, variables: nil)
  client = ShopifyAPI::Clients::Graphql::Admin.new(session: session)
  response = client.query(query: query, variables: variables)
  raise BillingError.new("Error while billing the store", []) unless response.ok?
  raise BillingError.new("Error while billing the store", response.body["errors"]) if response.body["errors"]
  response
end