import copyFile from 'browser/main/lib/dataApi/copyFile'
import {findStorage} from 'browser/lib/findStorage'
import filenamify from 'filenamify'

const fs = require('fs')
const path = require('path')

const LOCAL_STORED_REGEX = /!\[(.*?)]\(\s*?\/:storage\/(.*\.\S*?)\)/gi
const IMAGES_FOLDER_NAME = 'images'

/**
 * Export note together with images
 *
 * If images is stored in the storage, creates 'images' subfolder in target directory
 * and copies images to it. Changes links to images in the content of the note
 *
 * @param {String} storageKey or storage path
 * @param {String} noteContent Content to export
 * @param {String} targetPath Path to exported file
 * @param {function} outputFormatter
 * @return {Promise.<*[]>}
 */
function exportNote (storageKey, noteContent, targetPath, outputFormatter) {
  const storagePath = path.isAbsolute(storageKey) ? storageKey : findStorage(storageKey).path
  const exportTasks = []

  if (!storagePath) {
    throw new Error('Storage path is not found')
  }

  let exportedData = noteContent.replace(LOCAL_STORED_REGEX, (match, dstFilename, srcFilename) => {
    dstFilename = filenamify(dstFilename, {replacement: '_'})
    if (!path.extname(dstFilename)) {
      dstFilename += path.extname(srcFilename)
    }

    const dstRelativePath = path.join(IMAGES_FOLDER_NAME, dstFilename)

    exportTasks.push({
      src: path.join(IMAGES_FOLDER_NAME, srcFilename),
      dst: dstRelativePath
    })

    return `![${dstFilename}](${dstRelativePath})`
  })

  if (outputFormatter) {
    exportedData = outputFormatter(exportedData, exportTasks)
  }

  const tasks = prepareTasks(exportTasks, storagePath, path.dirname(targetPath))

  return Promise.all(tasks.map((task) => copyFile(task.src, task.dst)))
  .then(() => {
    return saveToFile(exportedData, targetPath)
  }).catch((err) => {
    rollbackExport(tasks)
    throw err
  })
}

function prepareTasks (tasks, storagePath, targetPath) {
  return tasks.map((task) => {
    if (!path.isAbsolute(task.src)) {
      task.src = path.join(storagePath, task.src)
    }

    if (!path.isAbsolute(task.dst)) {
      task.dst = path.join(targetPath, task.dst)
    }

    return task
  })
}

function saveToFile (data, filename) {
  return new Promise((resolve, reject) => {
    fs.writeFile(filename, data, (err) => {
      if (err) return reject(err)

      resolve(filename)
    })
  })
}

/**
 * Remove exported files
 * @param tasks Array of copy task objects. Object consists of two mandatory fields – `src` and `dst`
 */
function rollbackExport (tasks) {
  const folders = new Set()
  tasks.forEach((task) => {
    let fullpath = task.dst

    if (!path.extname(task.dst)) {
      fullpath = path.join(task.dst, path.basename(task.src))
    }

    if (fs.existsSync(fullpath)) {
      fs.unlink(fullpath)
      folders.add(path.dirname(fullpath))
    }
  })

  folders.forEach((folder) => {
    if (fs.readdirSync(folder).length === 0) {
      fs.rmdir(folder)
    }
  })
}

export default exportNote
