app/models/zuora_connect/app_instance_base.rb



module ZuoraConnect
  class AppInstanceBase < ActiveRecord::Base
    after_initialize :init
     self.table_name = "zuora_connect_app_instances"
    before_create :generate_access_token
    attr_accessor :options, :mode, :logins, :valid, :task_data, :last_refresh, :username, :password, :s3_client

    def init
      @options = Hash.new
      @logins = Hash.new
      if ZuoraConnect.configuration.mode == "Development"
        @s3_client = Aws::S3::Resource.new(region: ZuoraConnect.configuration.aws_region,access_key_id: ZuoraConnect.configuration.dev_mode_access_key_id,secret_access_key: ZuoraConnect.configuration.dev_mode_secret_access_key)
      else
        @s3_client = Aws::S3::Resource.new(region: ZuoraConnect.configuration.aws_region)
      end
      @valid = false
      self.attr_builder("timezone", ZuoraConnect.configuration.default_time_zone)
      self.attr_builder("locale", ZuoraConnect.configuration.default_locale)
      Apartment::Tenant.switch!(self.id)
      if( ActiveRecord::Migration.check_pending! != nil)
        Apartment::Migrator.migrate(self.id)
      end
      Thread.current[:appinstance] = self
    end

    def new_session(session: {}, username: self.access_token, password: self.refresh_token)
      @username = username
      @password = password
      @last_refresh = session["#{self.id}::last_refresh"]

      ## DEV MODE TASK DATA MOCKUP
      if ZuoraConnect.configuration.mode != "Production"
        self.options = ZuoraConnect.configuration.dev_mode_options
        ZuoraConnect.configuration.dev_mode_logins.each do |k,v|
          tmp = ZuoraConnect::Login.new(v)
          self.logins[k] = tmp
          self.attr_builder(k, tmp)
        end
        self.mode = ZuoraConnect.configuration.dev_mode_mode
      else
        if session.nil? || (!session.nil? && self.id != session["appInstance"].to_i) || session["#{self.id}::task_data"].blank? || ( session["#{self.id}::last_refresh"].blank? || session["#{self.id}::last_refresh"].to_i < ZuoraConnect.configuration.timeout.ago.to_i )
          Rails.logger.debug("REFRESHING - Session Nil") if session.nil?
          Rails.logger.debug("REFRESHING - AppInstance ID does not match session id") if  (!session.nil? && self.id != session["appInstance"].to_i)
          Rails.logger.debug("REFRESHING - Task Data Blank") if session["#{self.id}::task_data"].blank?
          Rails.logger.debug("REFRESHING - No Time on Cookie") if session["#{self.id}::last_refresh"].blank?
          Rails.logger.debug("REFRESHING - Session Old") if (session["#{self.id}::last_refresh"].blank? || session["#{self.id}::last_refresh"].to_i < ZuoraConnect.configuration.timeout.ago.to_i )
          self.refresh(session)
        else
          Rails.logger.debug("REBUILDING")
          build_task(session["#{self.id}::task_data"], session)
        end
      end
      I18n.locale = self.locale
      Time.zone = self.timezone
      @valid = true
    end

    def save_data(session = Hash.new)
      self.logins.each do |key, login|
        if login.tenant_type == "Zuora"
          if login.available_entities.size > 1 && Rails.application.config.session_store != ActionDispatch::Session::CookieStore
            login.available_entities.each do |entity_key|
              session["#{self.id}::#{key}::#{entity_key}:session"] = login.client(entity_key).current_session
            end
          else
            session["#{self.id}::#{key}:session"] = login.client.current_session
          end
        end
      end
      session["#{self.id}::task_data"] = self.task_data
      session["#{self.id}::last_refresh"] = self.last_refresh
      session["appInstance"] = self.id
      return session
    end

    def updateOption(optionId, value)
      if self.access_token && self.refresh_token
        return HTTParty.get(ZuoraConnect.configuration.url + "/api/v1/tools/application_options/#{optionId}/edit?value=#{value}",:basic_auth => auth = {:username => self.username, :password => self.password})
      else
        return false
      end
    end

    def refresh(session = nil)
      response = HTTParty.get(ZuoraConnect.configuration.url + "/api/v1/tools/tasks/#{self.id}.json",:basic_auth => auth = {:username => self.username, :password => self.password})
      if response.code == 200
        @last_refresh = Time.now.to_i
        build_task(JSON.parse(response.body), session)
      else
        raise ZuoraConnect::Exceptions::ConnectCommunicationError.new("Error Communicating with Connect", response.body, response.code)
      end
    end

    def build_task(task_data, session)
      @task_data = task_data
      @mode = @task_data["mode"]
      @task_data.each do |k,v|
        if k.match(/^(.*)_login$/)
          tmp = ZuoraConnect::Login.new(v)
          if !session.nil? && v["tenant_type"] == "Zuora"
            if tmp.entities.size > 0
              tmp.entities.each do |value|
                entity_id = value["id"]
                tmp.client(entity_id).current_session = session["#{self.id}::#{k}::#{entity_id}:session"] if !session.nil? && v["tenant_type"] == "Zuora" && session["#{self.id}::#{k}::#{entity_id}:session"]
              end
            else
              tmp.client.current_session = session["#{self.id}::#{k}:session"] if !session.nil? && v["tenant_type"] == "Zuora" && session["#{self.id}::#{k}:session"]
            end
          end
          @logins[k] = tmp
          self.attr_builder(k, @logins[k])
        elsif k == "options"
          v.each do |opt|
            @options[opt["config_name"]] = opt
          end
        elsif k == "user_settings"
          self.timezone =  v["timezone"]
          self.locale = v["local"]
        end
      end
    end

    def send_email

    end

    def upload_to_s3(local_file,s3_path = nil)
      s3_path = local_file.split("/").last if s3_path.nil?
      obj = @s3_client.bucket(ZuoraConnect.configuration.s3_bucket_name).object("#{ZuoraConnect.configuration.s3_folder_name}/#{self.id.to_s}/#{s3_path}}")
      obj.upload_file(local_file)
    end

    def get_s3_file_url(key)
      signer = Aws::S3::Presigner.new(client: @s3_client)
      url = signer.presigned_url(:get_object, bucket: ZuoraConnect.configuration.s3_bucket_name, key: "#{ZuoraConnect.configuration.s3_folder_name}/#{key}")
    end

    def self.decrypt_response(resp)
      OpenSSL::PKey::RSA.new(ZuoraConnect.configuration.private_key).private_decrypt(resp)
    end

    def attr_builder(field,val)
      singleton_class.class_eval { attr_accessor "#{field}" }
      send("#{field}=", val)
    end

    def generate_access_token
      begin
        self.token = SecureRandom.hex
      end while self.class.exists?(token: token)
    end

  end
end