module ZuoraConnect::Controllers::Helpers

def authenticate_connect_app_request

def authenticate_connect_app_request
  ElasticAPM.set_tag(:trace_id, request.uuid) if defined?(ElasticAPM) && ElasticAPM.running?
  Thread.current[:appinstance] = nil
  if request.headers['Zuora-Auth-Token'].present? && request.headers["NEWZUORA"].present?
    #Debug
    headers = request.headers.env.select do |k, _| 
      k.downcase.start_with?('http') ||
      k.in?(ActionDispatch::Http::Headers::CGI_VARIABLES)
    end
    puts headers
  
    #Do we need to refresh session identity
    zuora_host = request.headers["HTTP_X_FORWARDED_HOST"] || "apisandbox.zuora.com"
    zuora_client = ZuoraAPI::Login.new(url: "https://#{zuora_host}", session: cookies['ZSession'])
    zuora_entity_id = request.headers['ZuoraCurrentEntity']
    zuora_instance_id = params[:sidebar_launch].to_bool ? nil : (params[:app_instance_id] || session["appInstance"])
    #Identity blank or current entity different
    if (session["ZuoraCurrentIdentity"].blank? || session["ZuoraCurrentEntity"] != zuora_entity_id)
      begin
        identity, response = zuora_client.rest_call(url: zuora_client.rest_endpoint("identity"))
        session["ZuoraCurrentIdentity"] = identity
        session["ZuoraCurrentEntity"] = identity['entityId']
        raise ZuoraConnect::Exceptions::Error.new("Header entity id, '#{zuora_entity_id}' does not match identity call entity id, '#{identity['entityId']}'.") if zuora_entity_id != identity['entityId']
      rescue => ex
        ZuoraConnect.logger.error(ex)
        render "zuora_connect/static/invalid_launch_request", :locals => {:exception => ex}
        return              
      end
    end
    #Find matching app instances.
    if zuora_instance_id.present?
      appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host AND id = :id", entities: [zuora_entity_id], host: zuora_client.rest_domain, id: zuora_instance_id).pluck(:id, :name)
    else
      #if app_instance_ids is present then permissions still controlled by connect
      if params[:app_instance_ids].present? 
        begin
          navbar, response = zuora_client.rest_call(url: zuora_client.rest_endpoint("navigation"))
          
          urls = a['menus'].map {|x| x['url']}
          app_env = ENV["DEIS_APP"] || "xyz123"
          url = urls.compact.select {|url| File.basename(url).start_with?(app_env + '?')}.first
          task_ids = JSON.parse(Base64.urlsafe_decode64(CGI.parse(URI.parse(url).query)["app_instance_ids"][0]))
          
          appinstances = ZuoraConnect::AppInstance.where(:id => task_ids).pluck(:id, :name)
        rescue => ex
          ZuoraConnect.logger.error(ex)
          render "zuora_connect/static/invalid_launch_request", :locals => {:exception => ex}
          return
        end
      else
        appinstances = ZuoraConnect::AppInstance.where("zuora_entity_ids ?& array[:entities] = true AND zuora_domain = :host", entities: [zuora_entity_id], host: zuora_client.rest_domain).pluck(:id, :name)
      end
    end
    #One deployed instance
    if appinstances.size == 1
      ZuoraConnect.logger.debug("Instance is #{appinstances.to_h.keys.first}")
      session["appInstance"] = appinstances.to_h.keys.first
    #We have multiple, user must pick
    elsif appinstances.size > 1
      ZuoraConnect.logger.debug("User must select instance. #{@names}")
      @names = appinstances.to_h
      render "zuora_connect/static/launch"
      return
    else 
      #Create new app instance
      raise "Do not support new instance creation right now."
    end
  elsif params[:app_instance_ids].present? 
    if !params[:app_instance_id].present?
      begin
        app_instance_ids = JSON.parse(Base64.urlsafe_decode64(params[:app_instance_ids]))
        if app_instance_ids.length == 1
          verify_with_navbar
          instances = JSON.parse(Base64.urlsafe_decode64(CGI.parse(URI.parse(session[params[:app_instance_ids]]["url"]).query)["app_instance_ids"][0]))
          if instances.include?(app_instance_ids[0])
            @appinstance = ZuoraConnect::AppInstance.find(app_instance_ids[0])
            @appinstance.new_session(session: {})
            @appinstance.cache_app_instance
            session["appInstance"] = app_instance_ids[0]
          else
            ZuoraConnect.logger.error("Launch Error: Param Instance didnt match session data")
            render "zuora_connect/static/invalid_launch_request"
            return
          end
        else
          select_instance
          return
        end
      rescue => ex
        ZuoraConnect.logger.error(ex)
        render "zuora_connect/static/invalid_launch_request"
        return
      end     
    elsif params[:app_instance_id].present?
      begin
        instances = JSON.parse(Base64.urlsafe_decode64(CGI.parse(URI.parse(session[params[:app_instance_ids]]["url"]).query)["app_instance_ids"][0]))
        if instances.include?(params[:app_instance_id].to_i)
          @appinstance = ZuoraConnect::AppInstance.find(params[:app_instance_id].to_i)
          @appinstance.new_session(session: {})
          @appinstance.cache_app_instance
          session["appInstance"] = params[:app_instance_id].to_i
        else
          render "zuora_connect/static/invalid_launch_request"
          return
        end
      rescue => ex
        ZuoraConnect.logger.error(ex)
        render "zuora_connect/static/invalid_launch_request"
        return
      end
    end
  end
  start_time = Time.now
  if ZuoraConnect.configuration.mode == "Production"
    if request["data"] && /^([A-Za-z0-9+\/\-\_]{4})*([A-Za-z0-9+\/]{4}|[A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)$/.match(request["data"].to_s)
      setup_instance_via_data
    else
      setup_instance_via_session
    end
  else
    setup_instance_via_dev_mode
  end
  #Call .data_lookup with the current session to retrieve session. In some cases session may be stored/cache in redis 
  #so data lookup provides a model method that can be overriden per app.
  if params[:controller] != 'zuora_connect/api/v1/app_instance' && params[:action] != 'drop'
    if @appinstance.new_session_for_ui_requests(:params => params)
      @appinstance.new_session(:session => @appinstance.data_lookup(:session => session))
    end
  end
  if session["#{@appinstance.id}::user::email"].present? 
    ElasticAPM.set_user(session["#{@appinstance.id}::user::email"])  if defined?(ElasticAPM) && ElasticAPM.running?
    PaperTrail.whodunnit =  session["#{@appinstance.id}::user::email"] if defined?(PaperTrail)
  end
  begin
    I18n.locale = session["#{@appinstance.id}::user::locale"] ?  session["#{@appinstance.id}::user::locale"] : @appinstance.locale
  rescue I18n::InvalidLocale => ex
    ZuoraConnect.logger.error(ex) if !ZuoraConnect::AppInstance::IGNORED_LOCALS.include?(ex.locale.to_s.downcase)
  end
  Time.zone = session["#{@appinstance.id}::user::timezone"] ? session["#{@appinstance.id}::user::timezone"] : @appinstance.timezone
  ZuoraConnect.logger.debug("[#{@appinstance.blank? ? "N/A" : @appinstance.id}] Authenticate App Request Completed In - #{(Time.now - start_time).round(2)}s")
end