module Agents
  class TwitterActionAgent < Agent
    include TwitterConcern

    cannot_be_scheduled!

    description <<~MD
      The Twitter Action Agent is able to retweet or favorite tweets from the events it receives.

      #{twitter_dependencies_missing if dependencies_missing?}

      It expects to consume events generated by twitter agents where the payload is a hash of tweet information. The existing TwitterStreamAgent is one example of a valid event producer for this Agent.

      To be able to use this Agent you need to authenticate with Twitter in the [Services](/services) section first.

      Set `expected_receive_period_in_days` to the maximum amount of time that you'd expect to pass between Events being received by this Agent.
      Set `retweet` to either true or false.
      Set `favorite` to either true or false.
      Set `emit_error_events` to true to emit an Event when the action failed, otherwise the action will be retried.
    MD

    def validate_options
      unless options['expected_receive_period_in_days'].present?
        errors.add(:base, "expected_receive_period_in_days is required")
      end
      unless retweet? || favorite?
        errors.add(:base, "at least one action must be true")
      end
      if emit_error_events?.nil?
        errors.add(:base, "emit_error_events must be set to 'true' or 'false'")
      end
    end

    def working?
      last_receive_at && last_receive_at > interpolated['expected_receive_period_in_days'].to_i.days.ago && !recent_error_logs?
    end

    def default_options
      {
        'expected_receive_period_in_days' => '2',
        'favorite' => 'false',
        'retweet' => 'true',
        'emit_error_events' => 'false'
      }
    end

    def retweet?
      boolify(options['retweet'])
    end

    def favorite?
      boolify(options['favorite'])
    end

    def emit_error_events?
      boolify(options['emit_error_events'])
    end

    def receive(incoming_events)
      tweets = tweets_from_events(incoming_events)

      begin
        twitter.favorite(tweets) if favorite?
        twitter.retweet(tweets) if retweet?
      rescue Twitter::Error => e
        case e
        when Twitter::Error::AlreadyRetweeted, Twitter::Error::AlreadyFavorited
          error e.message
        else
          raise e unless emit_error_events?
        end
        if emit_error_events?
          create_event payload: {
            'success' => false,
            'error' => e.message,
            'tweets' => Hash[tweets.map { |t| [t.id, t.text] }],
            'agent_ids' => incoming_events.map(&:agent_id),
            'event_ids' => incoming_events.map(&:id)
          }
        end
      end
    end

    def tweets_from_events(events)
      events.map do |e|
        Twitter::Tweet.new(
          id: e.payload["id"],
          text: e.payload["expanded_text"] || e.payload["full_text"] || e.payload["text"]
        )
      end
    end
  end
end
