# frozen_string_literal: true

require 'pathname'
require 'cucumber/core/test/location'
require 'cucumber/core/test/around_hook'

module Cucumber
  # Hooks quack enough like `Cucumber::Core::Ast` source nodes that we can use them as
  # source for test steps
  module Hooks
    class << self
      def before_hook(id, location, &block)
        build_hook_step(id, location, block, BeforeHook, Core::Test::Action::Unskippable)
      end

      def after_hook(id, location, &block)
        build_hook_step(id, location, block, AfterHook, Core::Test::Action::Unskippable)
      end

      def after_step_hook(id, test_step, location, &block)
        raise ArgumentError if test_step.hook?

        build_hook_step(id, location, block, AfterStepHook, Core::Test::Action::Defined)
      end

      def around_hook(&block)
        Core::Test::AroundHook.new(&block)
      end

      private

      def build_hook_step(id, location, block, hook_type, action_type)
        action = action_type.new(location, &block)
        hook = hook_type.new(action.location)
        Core::Test::HookStep.new(id, hook.text, location, action)
      end
    end

    class AfterHook
      attr_reader :location

      def initialize(location)
        @location = location
      end

      def text
        'After hook'
      end

      def to_s
        "#{text} at #{location}"
      end

      def match_locations?(queried_locations)
        queried_locations.any? { |other_location| other_location.match?(location) }
      end

      def describe_to(visitor, *args)
        visitor.after_hook(self, *args)
      end
    end

    class BeforeHook
      attr_reader :location

      def initialize(location)
        @location = location
      end

      def text
        'Before hook'
      end

      def to_s
        "#{text} at #{location}"
      end

      def match_locations?(queried_locations)
        queried_locations.any? { |other_location| other_location.match?(location) }
      end

      def describe_to(visitor, *args)
        visitor.before_hook(self, *args)
      end
    end

    class AfterStepHook
      attr_reader :location

      def initialize(location)
        @location = location
      end

      def text
        'AfterStep hook'
      end

      def to_s
        "#{text} at #{location}"
      end

      def match_locations?(queried_locations)
        queried_locations.any? { |other_location| other_location.match?(location) }
      end

      def describe_to(visitor, *args)
        visitor.after_step_hook(self, *args)
      end
    end
  end
end
