const _ = require('lodash')
const qs = require('querystring')
const fetch = require('node-fetch').default
const FormData = require('form-data')
const guid = require('./utils/guid')

const getAccessToken = (client) => {
  const oauth1Token = _.get(client, 'qs.access_token')
  return client.accessToken || oauth1Token
}

const getDefaultOptions = () => {
  return {
    access: 'PUBLIC_INDEXABLE',
    ttl: 'P3M',
    overwrite: false,
    duplicateValidationStrategy: 'NONE',
    duplicateValidationScope: 'ENTIRE_PORTAL'
  }
}

const getFormData = ({ content, options, folderPath, fileName, folderId, charsetHunch }) => {
  const formData = new FormData()

  if (_.isNil(folderPath)) folderPath = '/'
  if (_.isNil(fileName)) fileName = guid()
  if (!_.isNil(folderId)) formData.append('folderId', folderId)
  if (!_.isNil(charsetHunch)) formData.append('charsetHunch', charsetHunch)

  formData.append('fileName', fileName)
  formData.append('file', Buffer.from(content), fileName)
  formData.append('options', JSON.stringify(Object.assign(getDefaultOptions(), options)))
  formData.append('folderPath', folderPath)

  return formData
}

const getUrlForFileUpload = (client) => {
  const hapikey = _.get(client, 'qs.hapikey')
  const params = {}
  if (hapikey) params.hapikey = hapikey
  const queryPart = _.isEmpty(params) ? '' : `?${qs.stringify(params)}`

  return `${client.baseUrl}/filemanager/api/v3/files/upload${queryPart}`
}

class File {
  constructor(client) {
    this.client = client
  }

  get() {
    return this.client.apiRequest({
      method: 'GET',
      path: '/filemanager/api/v2/files',
    })
  }

  getOne(id) {
    return this.client.apiRequest({
      method: 'GET',
      path: `/filemanager/api/v2/files/${id}`,
    })
  }

  /**
   * 
   * @param {url, options, folderPath, fileName, folderId, charsetHunch} fileData 
   * 
   * @see https://legacydocs.hubspot.com/docs/methods/files/v3/upload_new_file
   */
  async uploadByUrl(fileData) {
    const headers = {
      authorization: `Bearer ${getAccessToken(this.client)}`,
    }

    const fetchFileResult = await fetch(fileData.url, {
      method: 'GET',
      headers,
    })
    const content = await fetchFileResult.arrayBuffer()
    const uploadDetails = _.assign({}, fileData, { content })

    return this.upload(uploadDetails)
  }

  /**
   * 
   * @param {content, options, folderPath, fileName, folderId, charsetHunch} fileData 
   * 
   * @see https://legacydocs.hubspot.com/docs/methods/files/v3/upload_new_file
   */
  async upload(fileData) {
    const body = getFormData(fileData)
    const headers = body.getHeaders()
    headers.authorization = `Bearer ${getAccessToken(this.client)}`

    // can't use the request-promise based client because they don't handle formdata inside
    // of body correctly. See: https://github.com/request/request-promise/issues/271
    const result = await fetch(getUrlForFileUpload(this.client), {
      method: 'POST',
      body,
      headers,
    })

    return result.json()
  }
}

module.exports = File

@@ -1841,32 +1841,533 @@
 fileData %0A   * %0A
+   * @param %7Bstring%7D fileData.url Url of file.%0A   * @param %7BObject%7D fileData.options%0A   * @param %7Bstring%7D fileData.folderPath Partially optional field. One of folderPath or folderId must be specified.%0A   * @param %7Bstring%7D fileData.fileName Optional field. Desired name of the file.%0A   * @param %7Bstring%7D fileData.folderId Partially optional field. One of folderId or folderPath must be specified.%0A   * @param %7Bstring%7D fileData.charsetHunch Optional field. The character set of the provided file.%0A   * %0A
    * @see https:
@@ -2817,32 +2817,56 @@
 ils)%0A  %7D%0A%0A  /**%0A
+   * Upload a new file.%0A
    * %0A   * @para
@@ -2944,24 +2944,534 @@
 Data %0A   * %0A
+   * @param %7B*%7D      fileData.content content of file.%0A   * @param %7BObject%7D fileData.options %0A   * @param %7Bstring%7D fileData.folderPath Partially optional field. One of folderPath or folderId must be specified.%0A   * @param %7Bstring%7D fileData.fileName Optional field. Desired name of the file.%0A   * @param %7Bstring%7D fileData.folderId Partially optional field. One of folderId or folderPath must be specified.%0A   * @param %7Bstring%7D fileData.charsetHunch Optional field. The character set of the provided file.%0A   * %0A
    * @see ht

add comments