module Payments
  class PurchaseProfilesController < Payments::BaseController
    before_action :set_purchase_profile, only: [:show]

    def index
      authorize PurchaseProfile

      if params[:async]
        if email_purchase_profile_report(params.except(:async))
          flash[:success] = "Successfully emailed purchase profiles CSV to #{current_user.email}."
        else
          flash[:error] = "Failed to email purchase profiles to #{current_user.email}."
        end
        redirect_back
      else
        search_by_transaction_id unless params[:ext_transaction_id].blank?
        apply_purchase_profile_filters

        # TODO: Remove this block after deprecating the old download as CSV method.
        respond_to do |format|
          format.html
          format.csv { send_data to_csv, filename: "purchase-profiles-#{Date.today}.csv" }
        end
      end
      track_purchase_profiles_search!(params: params)
    end

    def show
      if @purchase_profile.state == 'migrated_v2'
        flash[:notice] = "IMPORTANT: This Purchase Profile has been migrated to Purchase Orders."
      end
    end

    def cancel
      authorize PurchaseProfile

      if PurchaseProfile.cancel(params[:purchase_profile_id])
        flash[:success] = "Subscription has been canceled and refunded"

        track_action! trackable_request
          .assemble_an
          .admin_panel_button(
            button: "purchase_profiles_terminate",
            purchase_profile_id: params[:purchase_profile_id]
          )
      else
        flash[:error] = "Failed to cancel purchase profile"
      end
      redirect_back
    end

    def do_not_renew
      authorize PurchaseProfile

      if PurchaseProfile.do_not_renew(params[:purchase_profile_id])
        flash[:success] = "Subscription will not renew"

        track_action! trackable_request
          .assemble_an
          .admin_panel_button(
            button: "purchase_profiles_do_not_renew",
            purchase_profile_id: params[:purchase_profile_id]
          )
      else
        flash[:error] = "Failed to DNR purchase profile"
      end
      redirect_back
    end

    def sync_ticket_access
      authorize PurchaseProfile

      if Payments::SyncTicketAccess.do(params[:purchase_profile_id])
        flash[:success] = "Successfully synced ticket access"

        track_action! trackable_request
          .assemble_an
          .admin_panel_button(
            button: "purchase_profiles_sync_ticket_access",
            purchase_profile_id: params[:purchase_profile_id]
          )
      else
        flash[:error] = "Failed to sync ticket access"
      end
      redirect_back
    end

    protected

    def email_purchase_profile_report(params)
      Payments::EmailPurchaseProfileReport.do(params.merge({
        admin_id: current_user.ldap_login,
        admin_email: current_user.email,
        full_details: true,
        per_page: 5000,
      }).reject { |_, v| v.blank? })
    end

    def set_purchase_profile
      authorize PurchaseProfile
      @purchase_profile = PurchaseProfile.find(params[:id] || params[:purchase_profile_id])

      if @purchase_profile.blank?
        flash[:error] = "No purchase profile found with ID: #{params[:id]}"
        redirect_to payments_purchase_profiles_path
        return
      end
    end

    # Search for a purchase_profile by purchase_payment ext_transaction_id
    def search_by_transaction_id
      purchase_payments = []
      # Try each payment_provider
      PurchaseProfile::PAYMENT_PROVIDERS.each do |prov|
        purchase_payments = PurchasePayment.filter(
          payment_provider: prov,
          ext_transaction_id: params[:ext_transaction_id]
        )
        break unless purchase_payments.blank?
      end

      if purchase_payments.blank?
        flash[:error] = "Unable to find purchase profile with the payments Ext Transaction ID: #{params[:ext_transaction_id]}"
        redirect_to payments_purchase_profiles_path
      else
        redirect_to payments_purchase_profile_path(purchase_payments.first.purchase_profile_id)
      end
    end

    def apply_purchase_profile_filters
      if params[:purchaser_login].present?
        user = Twitch::User.find_by_login(params[:purchaser_login])

        if user.blank?
          flash[:error] = "No user found with login: #{params[:purchaser_login]}"
          return redirect_to(payments_purchase_profiles_path)
        end

        params[:purchaser_id] = user.id
      end

      if params[:ticket_owner_login].present?
        user = Twitch::User.find_by_login(params[:ticket_owner_login])

        if user.blank?
          flash[:error] = "No user found with login: #{params[:ticket_owner_login]}"
          return redirect_to(payments_purchase_profiles_path)
        end

        params[:ticket_owner_id] = [user.id]
      end

      if params[:product_short_name].present?
        products = Subscriptions::TicketProduct.search(
          short_name: params[:product_short_name],
          exact_match: true
        )
        if products.blank?
          flash[:error] = "No product found with short name: #{params[:product_short_name]}"
          return redirect_to(payments_purchase_profiles_path)
        end
        params[:ticket_product_id] = products.map(&:id)
      end

      if params[:product_channel_login].present?
        user = Twitch::User.find_by_login(params[:product_channel_login])

        if user.blank?
          flash[:error] = "No user found with login: #{params[:product_channel_login]}"
          return redirect_to(payments_purchase_profiles_path)
        end

        products = Subscriptions::TicketProduct.search(
          channel_id: user.id,
          exact_match: true
        )

        params[:ticket_product_id] = products.map(&:id)
      end

      return @purchase_profiles = [] if purchase_profile_params.blank?

      params[:format] == "csv" ? params.merge!(full_details: false, per_page: "2000", page: 1) : params.merge!(full_details: true, per_page: "40")

      @purchase_profiles = PurchaseProfile.filter(purchase_profile_params)
      load_associations unless params[:format] == "csv" # params[:format] can be both nil and html for the normal view
    end

    private

    def purchase_profile_params
      params.permit(
        :purchaser_id,
        :purchaser_name,
        :purchaser_email,
        :state,
        :payment_provider,
        :ext_subscription_id,
        :ext_transaction_id,
        :created_on_start,
        :created_on_end,
        :page,
        :per_page,
        :full_details,
        ticket_owner_id: [],
        ticket_product_id: []
      ).to_h.reject { |_, v| v.blank? }
    end

    def load_associations
      jobs = []
      @purchase_profiles.each do |purchase_profile|
        jobs += purchase_profile.load_associations
      end

      jobs.map { |job| job.value(5) } # will block for a max of 5 seconds per job
    end

    def track_purchase_profiles_search!(params:)
      track_action! trackable_request.assemble_an.admin_panel_purchase_profiles_search(
        purchaser_login:        params[:purchaser_login],
        purchaser_name:         params[:purchaser_name],
        product_short_name:     params[:product_short_name],
        purchaser_email:        params[:purchaser_email],
        purchase_profile_state: params[:state],
        payment_provider:       params[:payment_provider],
        ext_subscription_id:    params[:ext_subscription_id],
        ticket_owner_login:     params[:ticket_owner_login],
        created_after_utc:      params[:created_on_start],
        created_before_utc:     params[:created_on_end],
        product_owner_login:    params[:product_channel_login],
        ext_transaction_id:     params[:ext_transaction_id]
      )
      return
    end

    def to_csv
      CSV.generate do |csv|
        csv << PurchaseProfile::CSV_HEADERS.values
        @purchase_profiles.each do |profile|
          csv << profile.to_csv_row
        end
      end
    end
  end
end
