module Chronos
  module Concerns
    extend ActiveSupport::Concern

    included do
      class_attribute :_chronos_scope
      class_attribute :_chronos_action_scope
      self._chronos_action_scope ||= {}
    end

    def chronos_scope_for(action)
      self.class._chronos_action_scope.fetch(action.to_sym, nil)
    end

    def chronos_job(job_type, job_key: nil,
                    scope: nil, scope_context: self, expires_at:, &block)
      scope ||= chronos_scope_for(action_name) || self.class._chronos_scope
      current_chronos_job ||= Chronos::Job.fetch(
        job_type,
        job_key: job_key,
        scope: scope,
        scope_context: scope_context,
        expires_at: expires_at)

      case
      when current_chronos_job.started?
        block.call(current_chronos_job)
        render_started!(current_chronos_job)
        # After this we mark it as running
        current_chronos_job.running!
      when current_chronos_job.running?
        render_running!(current_chronos_job)
      when current_chronos_job.finished?
        render_finished!(current_chronos_job)
      when current_chronos_job.errored?
        render_errored!(current_chronos_job)
      end
    end

    def retrieve_last_chronos_job(job_type,
                                  job_key: nil, scope: nil, scope_context: self)
      scope ||= chronos_scope_for(action_name) || self.class._chronos_scope
      Chronos::Job.retrieve_last(job_type,
                                 job_key: job_key,
                                 scope_context: scope_context,
                                 scope: scope)
    end

    def expire_chronos_job!(job_type,
                            job_key: nil, scope: nil, scope_context: self)
      job = retrieve_last_chronos_job(job_type,
                                      job_key: job_key,
                                      scope: scope,
                                      scope_context: scope_context)
      return unless job
      job.expire!
    end

    def render_started!(job)
      render json: { status: 'started' }
    end

    def render_running!(job)
      render json: { status: 'running',
        percentageCompletion: job.percentage_completion }
    end

    def render_finished!(job)
      render json: { status: 'finished' }
    end

    def render_errored!(job)
      render json: { status: 'errored', error: job.error }
    end

    private

    module ClassMethods
      def chronos_scope(default_scope)
        self._chronos_scope = default_scope
      end

      def chronos_scope_for(action, scope)
        self._chronos_action_scope[action.to_sym] = scope
      end
    end
  end
end
