'use strict'

const fs = require('graceful-fs')
const log = require('npmlog')
const path = require('path')

function getBaseConfigGypi () {
  const config = JSON.parse(JSON.stringify(process.config))
  if (!config.target_defaults) {
    config.target_defaults = {}
  }
  if (!config.variables) {
    config.variables = {}
  }
  return config
}

function getCurrentConfigGypi ({ gyp, nodeDir, vsInfo }) {
  const config = getBaseConfigGypi()
  const defaults = config.target_defaults
  const variables = config.variables

  // don't inherit the "defaults" from the base config.gypi.
  // doing so could cause problems in cases where the `node` executable was
  // compiled on a different machine (with different lib/include paths) than
  // the machine where the addon is being built to
  defaults.cflags = []
  defaults.defines = []
  defaults.include_dirs = []
  defaults.libraries = []

  // set the default_configuration prop
  if ('debug' in gyp.opts) {
    defaults.default_configuration = gyp.opts.debug ? 'Debug' : 'Release'
  }

  if (!defaults.default_configuration) {
    defaults.default_configuration = 'Release'
  }

  // set the target_arch variable
  variables.target_arch = gyp.opts.arch || process.arch || 'ia32'
  if (variables.target_arch === 'arm64') {
    defaults.msvs_configuration_platform = 'ARM64'
    defaults.xcode_configuration_platform = 'arm64'
  }

  // set the node development directory
  variables.nodedir = nodeDir

  // disable -T "thin" static archives by default
  variables.standalone_static_library = gyp.opts.thin ? 0 : 1

  if (process.platform === 'win32') {
    defaults.msbuild_toolset = vsInfo.toolset
    if (vsInfo.sdk) {
      defaults.msvs_windows_target_platform_version = vsInfo.sdk
    }
    if (variables.target_arch === 'arm64') {
      if (vsInfo.versionMajor > 15 ||
          (vsInfo.versionMajor === 15 && vsInfo.versionMajor >= 9)) {
        defaults.msvs_enable_marmasm = 1
      } else {
        log.warn('Compiling ARM64 assembly is only available in\n' +
          'Visual Studio 2017 version 15.9 and above')
      }
    }
    variables.msbuild_path = vsInfo.msBuild
  }

  // loop through the rest of the opts and add the unknown ones as variables.
  // this allows for module-specific configure flags like:
  //
  //   $ node-gyp configure --shared-libxml2
  Object.keys(gyp.opts).forEach(function (opt) {
    if (opt === 'argv') {
      return
    }
    if (opt in gyp.configDefs) {
      return
    }
    variables[opt.replace(/-/g, '_')] = gyp.opts[opt]
  })

  return config
}

function createConfigGypi ({ gyp, buildDir, nodeDir, vsInfo }, callback) {
  const configFilename = 'config.gypi'
  const configPath = path.resolve(buildDir, configFilename)

  log.verbose('build/' + configFilename, 'creating config file')

  const config = getCurrentConfigGypi({ gyp, nodeDir, vsInfo })

  // ensures that any boolean values in config.gypi get stringified
  function boolsToString (k, v) {
    if (typeof v === 'boolean') {
      return String(v)
    }
    return v
  }

  log.silly('build/' + configFilename, config)

  // now write out the config.gypi file to the build/ dir
  const prefix = '# Do not edit. File was generated by node-gyp\'s "configure" step'

  const json = JSON.stringify(config, boolsToString, 2)
  log.verbose('build/' + configFilename, 'writing out config file: %s', configPath)
  fs.writeFile(configPath, [prefix, json, ''].join('\n'), (err) => {
    callback(err, configPath)
  })
}

module.exports = createConfigGypi
module.exports.test = {
  getCurrentConfigGypi: getCurrentConfigGypi
}
