# frozen_string_literal: true

module Spree
  module Admin
    class PaymentsController < Spree::Admin::BaseController
      before_filter :load_order, except: [:show]
      before_filter :load_payment, only: [:fire, :show]
      before_filter :load_data
      before_filter :can_transition_to_payment

      respond_to :html

      def index
        @payments = @order.payments
        redirect_to new_admin_order_payment_url(@order) if @payments.empty?
      end

      def new
        @payment = @order.payments.build
      end

      def create
        @payment = @order.payments.build(object_params)
        load_payment_source

        begin
          unless @payment.save
            redirect_to admin_order_payments_path(@order)
            return
          end

          if @order.completed?
            @payment.process!
            flash[:success] = flash_message_for(@payment, :successfully_created)

            redirect_to admin_order_payments_path(@order)
          else
            AdvanceOrderService.new(@order).call!

            flash[:success] = Spree.t(:new_order_completed)
            redirect_to edit_admin_order_url(@order)
          end
        rescue Spree::Core::GatewayError => e
          flash[:error] = e.message.to_s
          redirect_to new_admin_order_payment_path(@order)
        end
      end

      # When a user fires an event, take them back to where they came from
      # (we can't use respond_override because Spree no longer uses respond_with)
      def fire
        event = params[:e]
        return unless event && @payment.payment_source

        # Because we have a transition method also called void, we do this to avoid conflicts.
        event = "void_transaction" if event == "void"
        if @payment.public_send("#{event}!")
          flash[:success] = t(:payment_updated)
        else
          flash[:error] = t(:cannot_perform_operation)
        end
      rescue Spree::Core::GatewayError => e
        flash[:error] = e.message
      ensure
        redirect_to request.referer
      end

      private

      def load_payment_source
        if @payment.payment_method.is_a?(Spree::Gateway) &&
           @payment.payment_method.payment_profiles_supported? &&
           params[:card].present? &&
           (params[:card] != 'new')
          @payment.source = CreditCard.find_by_id(params[:card])
        end
      end

      def object_params
        if params[:payment] &&
           params[:payment_source] &&
           source_params = params.delete(:payment_source)[params[:payment][:payment_method_id]]
          params[:payment][:source_attributes] = source_params
        end
        params[:payment]
      end

      def load_data
        @amount = params[:amount] || load_order.total

        # Only show payments for the order's distributor
        @payment_methods = PaymentMethod.
          available(:back_end).
          select{ |pm| pm.has_distributor? @order.distributor }

        @payment_method = if @payment && @payment.payment_method
                            @payment.payment_method
                          else
                            @payment_methods.first
                          end

        @previous_cards = @order.credit_cards.with_payment_profile
      end

      # At this point admin should have passed through Customer Details step
      # where order.next is called which leaves the order in payment step
      #
      # Orders in complete step also allows to access this controller
      #
      # Otherwise redirect user to that step
      def can_transition_to_payment
        return if @order.payment? || @order.complete?

        flash[:notice] = Spree.t(:fill_in_customer_info)
        redirect_to edit_admin_order_customer_url(@order)
      end

      def load_order
        @order = Order.find_by_number!(params[:order_id])
        authorize! action, @order
        @order
      end

      def load_payment
        @payment = Payment.find(params[:id])
      end
    end
  end
end
