#!/usr/bin/env node

// Get arguments
const [,, ...args] = process.argv

import os from 'os'
import fs from 'fs/promises'
import Util from './core/util.mjs'
import Core from './core/core.mjs'
import path from 'path'

if (!args.length) PrintHelp()
if (args[0] !== 'checkconfig' && args[0] !== 'install' && args[0] !== 'uninstall') PrintHelp

let configFile = 'config.json'
if (args[1]) {
  configFile = args[1]
}

const basicRunnerTemplate = `
import fs from 'fs'
import { runner } from 'service-core'

runner(import.meta.url, '${configFile}', 'db.json')
.then(
  function(core) {
    core.log.info('core is running')
  },
  function(err) {
    runner.log.error(err, 'Error starting runner')
    process.exit(1)
  }
)
`

const util = new Util(import.meta.url)

function PrintHelp() {
  console.log('')
  console.log('Usage: sccli <command> [config.json]')
  console.log('')
  console.log('<Commands>')
  console.log('  checkconfig : Test local config.json for errors')
  console.log('  install     : Install local config.json as service')
  console.log('  uninstall   : Uninstall local config.json as a service')
  console.log('')
  process.exit(1)
}

if (args[0] === 'checkconfig') {
  fs.readFile(configFile)
    .then(async function(content) {
      let config = JSON.parse(content)
      util.verifyConfig(config)

      let names = util.getAppNames(config)

      if (!names.length) {
        return Promise.reject(new Error('No application names were found'))
      }

      for (let name of names) {
        let provConstructor = Core.providers.get(config[name].provider)
        let provider = new provConstructor(config[name])
        await provider.checkConfig(config[name])
      }

      console.log(`${configFile} is a valid config with ${names.length} application${names.length > 1 ? 's' : ''}:`)
      for (let name of names) {
        console.log(`  * ${name} (${config[name].provider}${config[name].url ? ': ' + config[name].url : ' provider'})`)
      }
    })
    .catch(function(err) {
      console.log('Error checking config:', err)
      process.exit(2)
    })
    .then(function() {
      process.exit(0)
    })
} else if (args[0] === 'install') {
  if(os.platform() === 'win32') {
    const runner = path.join(process.cwd(), './runner.mjs')

    fs.stat(runner).catch(function() {
      console.log('Creating runner.mjs')
      return fs.writeFile(runner, basicRunnerTemplate)
    }).then(function() {
      console.log('Linking local service-core instance')
      return util.runCommand('npm', ['link', 'service-core'], null, function(stream) {
        console.log(stream.replace('\n', ''))
      })
    }).then(function() {
      return Promise.all([
        util.runCommand('npm', ['link', 'service-core'], null, function(stream) {
          console.log(stream.replace('\n', ''))
        }),
        fs.readFile(configFile),
        import('node-windows'),
      ])
    }).then(function([content, nodewindows]) {
      let config = JSON.parse(content)
      const Service = nodewindows.Service

      let serviceConfig = {
        name: config.title || config.name,
        description: config.description,
        script: runner,
        env: {
          name: 'NODE_ENV',
          value: 'production',
        },
        wait: 0,
        grow: .5,
        maxRestarts: 10
        //, workingDirectory: '...'
        //, allowServiceLogon: true
      }
      
      console.log('Service', serviceConfig)
      // Create a new service object
      let svc = new Service(serviceConfig);

      svc.on('install',function(){
        svc.start();
        process.exit(0)
      });
      
      svc.on('alreadyinstalled',function(){
        svc.start();
        process.exit(0)
      });
      
      svc.install();
    })
  } else {
    const runner = path.join(process.cwd(), './runner.mjs')

    fs.stat(runner).catch(function() {
      console.log('Creating runner.mjs')
      return fs.writeFile(runner, basicRunnerTemplate)
    }).then(function() {
      console.log('Linking local service-core instance')
      return util.runCommand('npm', ['link', 'service-core'], null, function(stream) {
        console.log(stream.replace('\n', ''))
      })
    }).then(function() {
      console.log('Runner is ready to be added to init.d')
    })
  }
} else if (args[0] === 'uninstall') {
  if(os.platform() === 'win32') {
    const runner = path.join(process.cwd(), './runner.mjs')

    fs.stat(runner).catch(function() {
      return fs.writeFile(runner, basicRunnerTemplate)
    }).then(function() {
      return Promise.all([
        fs.readFile(configFile),
        import('node-windows'),
      ])
    }).then(function([content, nodewindows]) {
      let config = JSON.parse(content)
      const Service = nodewindows.Service

      let serviceConfig = {
        name: config.title || config.name,
        description: config.description,
        script: runner,
        env: {
          name: 'NODE_ENV',
          value: 'production',
        },
        wait: 0,
        grow: .5,
        maxRestarts: 10
        //, workingDirectory: '...'
        //, allowServiceLogon: true
      }
      
      console.log('Service', serviceConfig)
      // Create a new service object
      let svc = new Service(serviceConfig);

      svc.on('uninstall',function(){
        console.log('Uninstall complete.');
        console.log('The service exists: ',svc.exists);
        process.exit(0)
      });

      svc.uninstall();
    })
  } else {
    console.log('non windows install targets are currently unsupported')
    process.exit(2)
  }
}
