module Reality
  module Miracles
    module EntityMethods
      extend Memoist

      def method_missing(name, *arg, &block)
        super if !arg.empty? && block.nil? && _symbolic_names.key?(name)
        _symbolic_names.fetch(name)
      end

      def respond_to_missing?(name, *)
        return false if name.to_s.start_with?('to_') # to_a, to_ary, to_h - they are definitely NOT here
        _symbolic_names.key?(name)
      end

      private

      memoize def _symbolic_names
        observations.group_by { |o| nameify(o.variable) }
          .map { |name, group|
            [name, Util.oneify(group.map(&:value))]
          }.to_h
      end

      def nameify(name)
        # TODO: Something(s) => somethings
        name.downcase.gsub(/\([^)]+\)/, '').gsub(/[^a-z_0-9]/, '_').sub(/(^_+|_+$)/, '').to_sym
      end
    end

    module LinkMethods
      extend Memoist

      def method_missing(name, *arg, &block)
        entity.public_send(name, *arg, &block)
      end

      def respond_to_missing?(name, *)
        return false if name.to_s.start_with?('to_') # to_a, to_ary, to_h - they are definitely NOT here
        entity.respond_to?(name)
      end

      private

      memoize def entity
        load
      end
    end
  end

  Entity.prepend Miracles::EntityMethods
  Link.prepend Miracles::LinkMethods
end
