require 'active_support/core_ext/hash'
require 'footrest/client'
require 'paul_walker'

module Bearcat
  class Client < Footrest::Client
    require 'bearcat/api_array'
    require 'bearcat/client/file_helper'
    require 'bearcat/client/assignments'
    require 'bearcat/client/courses'
    require 'bearcat/client/enrollments'
    require 'bearcat/client/outcome_groups'
    require 'bearcat/client/outcomes'
    require 'bearcat/client/sections'
    require 'bearcat/client/o_auth2'
    require 'bearcat/client/groups'
    require 'bearcat/client/group_categories'
    require 'bearcat/client/group_memberships'
    require 'bearcat/client/conferences'
    require 'bearcat/client/users'
    require 'bearcat/client/reports'
    require 'bearcat/client/accounts'
    require 'bearcat/client/submissions'
    require 'bearcat/client/conversations'
    require 'bearcat/client/modules'
    require 'bearcat/client/canvas_files'
    require 'bearcat/client/calendar_events'
    require 'bearcat/client/discussions'
    require 'bearcat/client/search'
    require 'bearcat/client/quizzes'
    require 'bearcat/client/assignment_groups'
    require 'bearcat/client/pages'
    require 'bearcat/client/files'
    require 'bearcat/client/folders'
    require 'bearcat/client/analytics'
    require 'bearcat/client/module_items'
    require 'bearcat/client/content_migrations'
    require 'bearcat/client/content_exports'
    require 'bearcat/client/custom_gradebook_columns'
    require 'bearcat/client/external_tools'

    include Assignments
    include Accounts
    include Analytics
    include Courses
    include Enrollments
    include OutcomeGroups
    include Outcomes
    include Sections
    include OAuth2
    include Groups
    include GroupCategories
    include GroupMemberships
    include Conferences
    include Users
    include Reports
    include Submissions
    include Conversations
    include Modules
    include CanvasFiles
    include CalendarEvents
    include Discussions
    include FileHelper
    include Search
    include Quizzes
    include AssignmentGroups
    include Pages
    include Files
    include Folders
    include ModuleItems
    include ContentMigrations
    include ContentExports
    include CustomGradebookColumns
    include ExternalTools

    # Override Footrest request for ApiArray support
    def request(method, &block)
      enforce_rate_limits
      response = connection.send(method, &block)
      apply_rate_limits(response.headers['x-rate-limit-remaining'])
      ApiArray.process_response(response, self)
    end

    def enforce_rate_limits
      return unless limit_remaining.present?
      return unless limit_remaining < Bearcat.rate_limit_min

      tts = ((Bearcat.rate_limit_min - limit_remaining) / 5).ceil
      tts = Bearcat.min_sleep_seconds if tts < Bearcat.min_sleep_seconds
      tts = Bearcat.max_sleep_seconds if tts > Bearcat.max_sleep_seconds


      message = "Canvas API rate limit minimum #{Bearcat.rate_limit_min} reached. "\
        "Sleeping for #{tts} second(s) to catch up ~zzZZ~. "\
        "Limit Remaining: #{limit_remaining}"
      Bearcat.logger.debug(message)

      sleep(tts)
    end

    def apply_rate_limits(limit)
      return if limit.nil?
      self.limit_remaining = limit.to_i
    end

    def using_master_rate_limit?
      config[:master_rate_limit].present? || Bearcat.master_rate_limit.present?
    end

    def limit_remaining
      if using_master_rate_limit?
        Bearcat.master_mutex.synchronize do
          limit = PaulWalker::RateLimit.get(config[:token], config[:token])
          if limit.nil?
            PaulWalker::RateLimit.add(config[:token], config[:token], 0, Bearcat::rate_limit_min)
            limit = { current: 0 }.with_indifferent_access
          end
          Bearcat.logger.debug limit['current'].to_s
          limit['current']
        end
      else
        Bearcat.rate_limits[config[:token]]
      end
    end

    def limit_remaining=(value)
      if using_master_rate_limit?
        Bearcat.master_mutex.synchronize do
          PaulWalker::RateLimit.add(config[:token], config[:token], value, Bearcat::rate_limit_min)
        end
      else
        Bearcat.rate_limits[config[:token]] = value
      end
    end
  end
end