require 'socket'

module Propono
  class PublisherError < ProponoError
  end

  class Publisher
    def self.publish(*args)
      new(*args).publish
    end

    attr_reader :aws_client, :propono_config, :topic_name, :message, :id, :async

    def initialize(aws_client, propono_config, topic_name, message, async: false, id: nil)
      raise PublisherError.new("Topic is nil") if topic_name.nil?
      raise PublisherError.new("Message is nil") if message.nil?

      @aws_client = aws_client
      @propono_config = propono_config
      @topic_name = topic_name
      @message = message
      @async = async

      random_id = SecureRandom.hex(3)
      @id = id ? "#{id}-#{random_id}" : random_id
    end

    def publish
      propono_config.logger.info "Propono [#{id}]: Publishing #{message} to #{topic_name}"
      async ? publish_asyncronously : publish_syncronously
    end

    private

    def publish_asyncronously
      Thread.new { publish_syncronously }
    end

    def publish_syncronously
      begin
        topic = aws_client.create_topic(topic_name)
      rescue => e
        propono_config.logger.error "Propono [#{id}]: Failed to get or create topic #{topic_name}: #{e}"
        raise
      end

      begin
        aws_client.publish_to_sns(topic, body)
      rescue => e
        propono_config.logger.error "Propono [#{id}]: Failed to send via sns: #{e}"
        raise
      end
    end

    def body
      {
        id: id,
        message: message
      }
    end
  end
end
