// Native
const { homedir } = require('os')
const path = require('path')

// Packages
const fs = require('fs-extra')
const ms = require('ms')

// Ours
const { get: getUser } = require('./user')

// `8h` is arbitrarily used based on the average sleep time
const TTL = ms('8h')

let file = process.env.NOW_JSON
  ? path.resolve(process.env.NOW_JSON)
  : path.resolve(homedir(), '.now.json')

function setConfigFile(nowjson) {
  file = path.resolve(nowjson)
}

function save(data) {
  fs.writeFileSync(file, JSON.stringify(data, null, 2))
}

/**
 * Reads the config file
 *
 * Optionally, always queries the API to get the user info even if the
 * config file is not present
 *
 * @param  {Boolean} force [false] Queries the API even if the config
 *                                 file is not present. If `true`, `token`
 *                                 *must* be specified
 * @param  {String}  token         Will be used to autenticate in the API
                                   if needed
 * @param  {String}  apiUrl        URL of the API to be used
 * @return {Object}
 */
async function read({ force = false, token, apiUrl } = {}) {
  let existing = {}
  try {
    existing = fs.readFileSync(file, 'utf8')
    existing = JSON.parse(existing)
  } catch (err) {}

  // Will happen if `force`d or if `--token` is used and it's different from
  // The one that's stored (which can be `undefined`)
  if ((force && token) || (token && token !== existing.token)) {
    const user = await getUser({ token, apiUrl })
    if (user) {
      return {
        token,
        user: {
          uid: user.uid,
          username: user.username,
          email: user.email
        }
      }
    }
    return {}
  }

  if (!existing.token) {
    return {}
  }

  if (!existing.lastUpdate || Date.now() - existing.lastUpdate > TTL) {
    // TODO: update `teams` info
    const token = existing.token
    const user = await getUser({ token })

    if (user) {
      existing.user = user
      existing.lastUpdate = Date.now()
      save(existing)
    }
  }
  return existing
}

/**
 * Merges the `data` object onto the
 * JSON config stored in `.now.json`.
 *
 * (atomic)
 * @param {Object} data
 */
async function merge(data) {
  const cfg = Object.assign({}, await read(), data)
  save(cfg)
}

// Removes a key from the config and store the result
async function remove(key) {
  const cfg = await read()
  delete cfg[key]
  fs.writeFileSync(file, JSON.stringify(cfg, null, 2))
}

// We need to remove the config file when running `now logout`
const removeFile = async () => fs.remove(file)

module.exports = {
  setConfigFile,
  read,
  merge,
  remove,
  removeFile
}