/*
 * Copyright (c) 2015-2016 TechnologyAdvice
 */

'use strict'

class SQSStub {
  constructor(msgCount, timeout) {
    this.msgs = []
    this.timeout = timeout === undefined ? 20 : timeout
    this.msgCount = msgCount
    this.config = {
      region: 'us-east-1',
      endpoint: 'http://foo.bar'
    }
    for (let i = 0; i < msgCount; i++) {
      this._addMessage(i)
    }
  }

  createQueue(params) {
    return this.getQueueUrl(params)
  }

  deleteMessageBatch(params) {
    return this._makeReq(() => {
      const res = {
        Successful: [],
        Failed: []
      }
      params.Entries.forEach((entry) => {
        if (parseInt(entry.ReceiptHandle, 10) < this.msgCount) {
          res.Successful.push({Id: entry.Id})
        } else {
          res.Failed.push({
            Id: entry.Id,
            SenderFault: true,
            Code: '404',
            Message: 'Does not exist'
          })
        }
      })
      return Promise.resolve(res)
    })
  }

  deleteQueue() {
    return this._makeReq(() => {
      return Promise.resolve({ ResponseMetadata: { RequestId: 'd2206b43-df52-5161-a8e8-24dc83737962' } })
    })
  }

  getQueueUrl(params) {
    return this._makeReq(() => {
      return Promise.resolve({
        QueueUrl: `http://localhost:9324/queues/${params.QueueName}`
      })
    })
  }

  receiveMessage(params) {
    return this._makeReq(() => {
      const msgs = this.msgs.splice(0, params.MaxNumberOfMessages)
      return new Promise((resolve, reject) => {
        if (msgs.length) return resolve({Messages: msgs})
        const timeout = setTimeout(() => {
          resolve({})
        }, this.timeout * 1000)
        this._makeAbort(reject, timeout)
        return undefined
      })
    })
  }

  sendMessage(params) {
    this._addMessage(params.QueueUrl, params.MessageBody)
    return this._makeReq(() => {
      return Promise.resolve({
        MessageId: 'd2206b43-df52-5161-a8e8-24dc83737962',
        MD5OfMessageAttributes: 'deadbeefdeadbeefdeadbeefdeadbeef',
        MD5OfMessageBody: 'deadbeefdeadbeefdeadbeefdeadbeef'
      })
    })
  }

  sendMessageBatch(params) {
    const res = {
      Successful: [],
      Failed: []
    }
    params.Entries.forEach((entry, idx) => {
      if (entry.MessageBody !== 'FAIL') {
        this._addMessage(entry.Id, entry.MessageBody)
        res.Successful.push({
          Id: entry.Id,
          MessageId: idx.toString(),
          MD5OfMessageAttributes: 'deadbeefdeadbeefdeadbeefdeadbeef',
          MD5OfMessageBody: 'deadbeefdeadbeefdeadbeefdeadbeef'
        })
      } else {
        res.Failed.push({
          Id: entry.Id,
          SenderFault: true,
          Code: 'Message is empty',
          Message: ''
        })
      }
    })
    return this._makeReq(() => Promise.resolve(res))
  }

  _addMessage(id, body) {
    this.msgs.push({
      MessageId: `id_${id}`,
      ReceiptHandle: `${id}`,
      Body: body || `{"num": ${id}}`
    })
  }

  _makeAbort(reject, timeout) {
    this._abort = () => {
      if (timeout) clearTimeout(timeout)
      const err = new Error('Request aborted by user')
      err.code = err.name = 'RequestAbortedError'
      err.retryable = false
      err.time = new Date()
      reject(err)
    }
  }

  _makeReq(func) {
    const nop = () => {}
    return {
      promise: func,
      abort: this._abort || nop
    }
  }
}

module.exports = SQSStub

@@ -64,20 +64,94 @@
 '%0A%0Ac
-lass SQSStub
+onst EventEmitter = require('events').EventEmitter%0A%0Aclass SQSStub extends EventEmitter
  %7B%0A 
@@ -176,32 +176,44 @@
 unt, timeout) %7B%0A
+    super()%0A
     this.msgs = 
@@ -1640,16 +1640,55 @@
  msgs%7D)%0A
+        let removeListeners = () =%3E %7B%7D%0A
         
@@ -1718,24 +1718,52 @@
 out(() =%3E %7B%0A
+          removeListeners()%0A
           re
@@ -1799,56 +1799,656 @@
 eout
- * 1000)%0A        this._makeAbort(reject, timeout
+)%0A        const onAbort = () =%3E %7B%0A          removeListeners()%0A          const err = new Error('Request aborted by user')%0A          err.code = err.name = 'RequestAbortedError'%0A          err.retryable = false%0A          err.time = new Date()%0A          reject(err)%0A        %7D%0A        const onNewMessage = (msg) =%3E %7B%0A          removeListeners()%0A          resolve(%7BMessages: %5Bmsg%5D%7D)%0A        %7D%0A        removeListeners = () =%3E %7B%0A          clearTimeout(timeout)%0A          this.removeListener('newMessage', onNewMessage)%0A          this.removeListener('abort', onAbort)%0A        %7D%0A        this.once('abort', onAbort)%0A        this.once('newMessage', onNewMessage
 )%0A  
@@ -3706,294 +3706,66 @@
 )%0A  
-%7D%0A%0A  _makeAbort(reject, timeout) %7B%0A    this._abort = () =%3E %7B%0A      if (timeout) clearTimeout(timeout)%0A      const err = new Error('Request aborted by user')%0A      err.code = err.name = 'RequestAbortedError'%0A      err.retryable = false%0A      err.time = new Date()%0A      reject(err)%0A    %7D
+  this.emit('newMessage', this.msgs%5Bthis.msgs.length - 1%5D)
 %0A  %7D
@@ -3789,33 +3789,8 @@
 ) %7B%0A
-    const nop = () =%3E %7B%7D%0A
     
@@ -3836,26 +3836,36 @@
 rt: 
-this._abort %7C%7C nop
+() =%3E %7B this.emit('abort') %7D
 %0A   

Make receiveMessage mock more useful