# typed: true

# Copyright (c) 2015 Sqreen. All Rights Reserved.
# Please refer to our terms for more information: https://www.sqreen.com/terms.html

require 'sqreen/exception'
require 'sqreen/log'

module Sqreen
  class CB
    # Callback class.
    #
    # Three methods can be defined:
    # - pre(*args, &block)
    #   To be called prior to the hooked method.
    # - post(return_value, *args, &block)
    #   To be called after the hooked method. The return_value argument is
    #   the value returned by the hooked method.
    # - failing(exception, ...)
    #   To be called when the method raise
    # The method pre, post and exception may return nil or a Hash.
    #  - nil: the original method is called and the callback has no further
    #    effect
    #  - { :status => :skip }: we skip the original method call
    #  - { :status => :raise}:
    #
    #  - nil: the original return value is returned, as if coallback had no
    #    effect
    #  - { :status => :raise}:
    #  - { :status => :override }:
    #
    #  - nil: reraise
    #  - { :status => :reraise }: reraise
    #  - { :status => :override }: eat exception
    #  - { :retry => :retry }: try the block again
    #
    #  CB can also declare that they are whitelisted and should not be run at the moment.

    DEFAULT_PRIORITY = 100

    attr_reader :klass, :method
    attr_reader :overtimeable

    def initialize(klass, method)
      @method = method
      @klass = klass

      @has_pre  = respond_to? :pre
      @has_post = respond_to? :post
      @has_failing = respond_to? :failing
      @overtimeable = false

      raise(Sqreen::Exception, 'No callback provided') unless @has_pre || @has_post || @has_failing
    end

    def whitelisted?
      false
    end

    # the lower, the closer to the beginning of the list
    def priority
      DEFAULT_PRIORITY
    end

    def pre?
      @has_pre
    end

    def post?
      @has_post
    end

    def failing?
      @has_failing
    end

    def to_s
      format('#<%s: %s.%s>', self.class, @klass, @method)
    end

    def overtime!
      Sqreen.log.debug { "#{self} is overtime!" }
      @overtimeable
    end

    def framework
      nil
    end
  end
end