require "hashie" require "erb" require "socrates/configuration" require "socrates/logger" require "socrates/string_helpers" require "socrates/core/state_data" module Socrates module Core module State attr_reader :data, :context def initialize(data: StateData.new, adapter:, channel:, user:) @data = data @adapter = adapter @channel = channel @user = user @next_state_id = nil @next_state_action = nil @logger = Socrates.config.logger || Socrates::Logger.default end def next_state_id if @next_state_id.nil? state_id_from_classname else @next_state_id end end def next_state_action if @next_state_action.nil? next_action(@data.state_action) else @next_state_action end end def respond(message: nil, template: nil) if template # TODO: Partials? filename = File.join(Socrates.config.view_path, template) source = File.read(filename) message = ERB.new(source, 0, "<>").result(binding) end return if message.empty? @logger.info %Q(#{@channel} send: "#{format_for_logging(message)}") @adapter.send_message(message, @channel) end def send_message(to:, message:) displayable_to = to.respond_to?(:id) ? to.id : to @logger.info %Q(#{@channel} send direct to #{displayable_to}: "#{format_for_logging(message)}") @adapter.send_direct_message(message, to) end def transition_to(state_id, action: nil, data: {}) if action.nil? action = if state_id.nil? nil elsif state_id == state_id_from_classname next_action(@data.state_action) else :ask end end @next_state_id = state_id @next_state_action = action @data.merge(data) end def repeat_action @next_state_id = @data.state_id @next_state_action = @data.state_action end def end_conversation @data.clear transition_to StateData::END_OF_CONVERSATION, action: StateData::END_OF_CONVERSATION end def ask # stub implementation, to be overwritten. end def listen(_message) # stub implementation, to be overwritten. end private def next_action(current_action) (%i[ask listen] - [current_action]).first end def format_for_logging(message) message.gsub("\n", "\\n") end def state_id_from_classname StringHelpers.classname_to_underscore(self.class.to_s.split("::").last).to_sym end end end end