noflo = require 'noflo'
knox = require 'knox'
dataurl = require 'dataurl'
uuid = require 'uuid'

upload = (client, blocks, data, out, callback) ->
  unless blocks.length
    out.send data
    do callback
    return

  block = blocks.shift()
  src = block.cover?.src or block.src
  parsed = dataurl.parse src
  ext = ''
  switch parsed.mimetype
    when 'image/png'
      ext = '.png'
    when 'image/gif'
      ext = '.gif'
    when 'image/jpeg'
      ext = '.jpg'
  keyName = "/#{uuid.v4()}#{ext}"
  req = client.put keyName,
    'Content-Type': parsed.mimetype
    'Content-Length': parsed.data.length
  req.on 'response', (res) ->
    unless res.statusCode is 200
      return callback new Error "Failed to upload image: #{res.statusCode}"
    block.src = client.http keyName
    block.cover.src = client.http keyName if block.cover
    block.html = block.html.replace src, client.http keyName
    upload client, blocks, data, out, callback
  req.end parsed.data

exports.getComponent = ->
  c = new noflo.Component
  c.description = 'Handle data URLs in image blocks'
  c.inPorts.add 'in',
    datatype: 'object'
    required: yes
  c.inPorts.add 'key',
    datatype: 'string'
    required: yes
  c.inPorts.add 'secret',
    datatype: 'string'
    required: yes
  c.inPorts.add 'bucket',
    datatype: 'string'
    required: yes
  c.inPorts.add 'region',
    datatype: 'string'
    required: yes
  c.outPorts.add 'out',
    datatype: 'object'
    required: yes
  c.outPorts.add 'error',
    datatype: 'object'

  noflo.helpers.WirePattern c,
    in: 'in'
    params: ['key', 'secret', 'bucket', 'region']
    out: 'out'
    async: true
    forwardGroups: true
  , (data, groups, out, callback) ->
    unless data.content
      callback new Error 'No content available'
    dataUrls = data.content.filter (block) ->
      return false unless block.type is 'image'
      src = block.cover?.src or block.src
      return false unless src
      return false unless src.indexOf('data:') is 0
      true

    unless dataUrls.length
      out.send data
      do callback
      return

    unless c.params?.key and c.params?.secret and c.params?.bucket
      callback new Error "#{dataUrls.length} data URLs in content but S3 not configured"
      return

    client = knox.createClient
      key: c.params.key
      secret: c.params.secret
      bucket: c.params.bucket
      region: c.params.region
    upload client, dataUrls, data, out, callback

  c
