#!/usr/bin/env node
import chalk from 'chalk'
import inquirer from 'inquirer'
import { execSync } from 'child_process'
import { detectOS, updateSoftware, installRequired, setNodeVersion } from './scripts/system.js'
import { checkAoEnvFile, aoEnv, setAoEnv, AO_ENV_FILE_PATH } from './scripts/settings.js'
import { unicornPortal, asciiArt, clearScreen, spinnerWait } from './scripts/console.js'
import { welcome, exclaim, roger, farewell } from './scripts/welcome.js'
import { printManualPage, manualFolderAsMenu, AO_MANUAL_PATH } from './scripts/manual.js'
import { isFolder } from './scripts/files.js'
import { sleep } from './scripts/util.js'
import { tests } from './scripts/tests.js'
import { headerStyle } from './scripts/chalkStyles.js'
import './scripts/strings.js'
import { installAoAlias, downloadManual, updateManual } from './scripts/features.js'
import { startPublicBootstrap } from './scripts/bootstrap.js'

// These should become .env variables that are loaded intelligently
let distro
let memberName

// This does not work
function exitIfRoot() {
  try {
    execSync('[ "$EUID" -eq 0 ]')
    console.log(`${chalk.red.bold(exclaim())} Seems you're running this script as a superuser.`)
    console.log('That might cause some issues with permissions and whatnot. Run this script as your default user (without sudo) and I\'ll ask you when I need superuser permissions')
    process.exit(1)
  } catch(err) {}
}

// Prints the AO Main Menu and executes the user's choice
async function mainMenu() {
  console.log(`\n${headerStyle('AO Main Menu')}\n`)
  const mainMenuChoices = [
    'Chat',
    'Alchemy',
    'Deck',
    'Admin',
    'Tests',
    'Manual',
    'Log Out',
    'Exit',
  ]
  const answer = await inquirer.prompt({
    name: 'main_menu',
    type: 'list',
    message: 'Please choose:',
    choices: mainMenuChoices,
    pageSize: mainMenuChoices.length
  })
  switch(answer.main_menu) {
    case 'Chat':
      while(await chatMenu()) {}
      break
    case 'Alchemy':
      while(await alchemyMenu()) {}
      break
    case 'Deck':
      await todoList('My Todo List', ['Add full AO install process to ao-cli in convenient format', 'Add AO server unit tests to ao-cli', 'Get groceries', 'Play music every day'])
      break
    case 'Admin':
      while(await adminMenu()) {}
      break
    case 'Tests':
      while(await testsMenu()) {}
      break
    case 'Manual':
      if(!isFolder(AO_MANUAL_PATH)) {
        console.log("Downloading the AO manual...")
        if(downloadManual()) {
          console.log("Downloaded the AO Manual from the official git repo via http and saved to", AO_MANUAL_PATH + '.')
        } else {
          console.log('Failed to download the AO manual, sorry.')
          return false
        }
      } else {
        updateManual()
      }
      await printManualPage(AO_MANUAL_PATH) // Fencepost case - print overview page
      let previousChoice = 0
      do {
        previousChoice = await manualFolderAsMenu(AO_MANUAL_PATH, 'AO User Manual', 'Back to Main Menu', previousChoice + 1)
      } while(previousChoice !== false)
      break
    case 'Log Out':
      await spinnerWait('Logging out... (just kidding)')
      break
    case 'Exit':
      farewell()
      await sleep(310)
      return false
  }
  return true
}

// Prints a menu that allows you to join the global AO chatrooms
let publicBootstrapStarted = false
async function chatMenu() {
  let answers = {}
  const PUBLIC_BOOTSTRAP_ENABLED = aoEnv('PUBLIC_BOOTSTRAP_ENABLED')
  if(PUBLIC_BOOTSTRAP_ENABLED) {
    // They previously enabled public bootstrapping, so check to make sure it is working and then hide the option
    // todo: start and then verify functioning of p2p boostrap method here
    // if it's already started don't start it again
    if(!publicBootstrapStarted) {
      console.log("\nBootstrapping public AO swarm...")
      startPublicBootstrap()
      console.log("Bootstrapped (just kidding)")
      publicBootstrapStarted = true
    }
    //answers['chat_menu'] = 'Enable p2p bootstrap'
  }
  const publicBootstrapMenuItem = PUBLIC_BOOTSTRAP_ENABLED ? 'Disable p2p bootstrap' : 'Enable p2p bootstrap'
  const chatChoices = [
    publicBootstrapMenuItem,
    'Join public chatroom',
    'Join chatroom',
    'Address Book',
    'Back to Main Menu',
  ]
  console.log(`\n${headerStyle('AO Public Chatrooms')}\n`)
  const answer = await inquirer.prompt({
    name: 'chat_menu',
    type: 'list',
    message: 'Please choose:',
    choices: chatChoices
  })
  switch(answer.chat_menu) {
    case 'Enable p2p bootstrap':
      console.log('In order to join AO public chatrooms, AO uses the hyperswarm protocol. Joining hyperswarm may expose your IP address to other users. (For high-security installations, don\'t use public bootstrap: you can still add tor addresses to your address book manually and join those chatrooms by name.)')
      setAoEnv('PUBLIC_BOOTSTRAP_ENABLED', true)
      //message: Type \'public\' and press Enter to enable:')
      break
    case 'Disable p2p bootstrap':
      setAoEnv('PUBLIC_BOOTSTRAP_ENABLED', false)
      console.log(roger(), 'Disabled public bootstrapping.')
      if(publicBootstrapStarted) {
        // stop the bootstrap thing here
        publicBootstrapStarted = false
      }
      break
    case 'Join public chatroom':
      console.log('Not yet implemented')
      break
    case 'Join chatroom':
      console.log('Not yet implemented')
      break
    case 'Address Book':
      console.log('The point of this address book is to make it possible to type short, one-word names and have them resolve to tor addresses.')
      console.log('Name a piece of data by saying name=data. For example, doge=5uc41o1...onion. Then \'doge\' will return the .onion address.')
      console.log('Querying with any synonym in a chain will return the final meanings they all point to.')
      console.log('Keys can have multiple values.')
      break
    case 'Back to Main Menu':
      return false
  }
  return true
}

// Prints the AO Admin Menu and executes the user's choice
async function adminMenu() {
  console.log(`\n${headerStyle('AO Admin Menu')}`)
  const adminChoices = [
    'Install \'ao\' alias for \'ao-cli\'',
    'Check AO install',
    'Update AO',
    'Configure AO features',
    'Switch AO database',
    'Import/Export state/decks',
    'Check AO service',
    'Watch logs now',
    'Start/Stop AO service',
    'Back to Main Menu'
  ]
  const answer = await inquirer.prompt({
    name: 'admin_menu',
    type: 'list',
    message: 'Please choose:',
    choices: adminChoices,
    pageSize: adminChoices.length,
  })
  switch(answer.admin_menu) {
    case adminChoices[0]:
      installAoAlias()
      break
    case adminChoices[1]:
    case adminChoices[2]:
    case adminChoices[3]:
      while(await featuresMenu()) {}
      break
    case adminChoices[4]:
    case adminChoices[5]:
    case adminChoices[6]:
    case adminChoices[7]:
    case adminChoices[8]:
      console.log("Not yet implemented.")
      break
    default:
      return false
  }
  return true
}

// Prints the AO Unit Tests Menu and executes the user's choice
async function testsMenu() {
  console.log(`\n${headerStyle('AO Unit Tests')}`)
  let testChoices = Object.entries(tests).map(([menuTitle, testFunction]) => {
    return menuTitle
  })
  testChoices.push('Back to Main Menu')
  const answer = await inquirer.prompt({
    name: 'tests_menu',
    type: 'list',
    message: 'Please choose:',
    choices: testChoices
  })
  if(answer.tests_menu === 'Back to Main Menu') {
    return false
  }
  const testFunction = tests[answer.tests_menu]
  if(testFunction) await testFunction()
  return true
}

// Prints the AO Admin Menu and executes the user's choice
async function alchemyMenu() {
  console.log(`\n${headerStyle('Alchemy')}`)
  const alchemyChoices = [
    'Update software',
    'Install AO prerequisites',
    'Check bitcoin status',
    'Back to Main Menu'
  ]
  const answer = await inquirer.prompt({
    name: 'alchemy_menu',
    type: 'list',
    message: 'Please choose:',
    choices: alchemyChoices
  })
  switch(answer.alchemy_menu) {
    case alchemyChoices[0]:
      updateSoftware()
      break
    case alchemyChoices[1]:
      installRequired()
      break
    case alchemyChoices[2]:
      let stdout = execSync('source ~/Alchemy/ingredients/lead && source ~/Alchemy/ingredients/gold && bitcoin_is_synced')
      console.log(`${stdout}`)
      break
    default:
      return false
  }
  return true
}

// Prints the Configure AO Features menu and executes the user's choice
async function featuresMenu() {
  console.log(`\n${headerStyle('Configure AO Features')}`)
  const features = [
    'nginx              host AO publicly over the world wide web',
    'SSL/Certbot        HTTPS for public web AO',                
    'Tor                connect AOs p2p',
    'Bitcoin            payments',
    'Lightning          payments',
    'Jitsi              secure video chat',
    'Signal             notifications',
    'File hosting       file attachments on cards',
    'youtube-dl         cache web videos',
    'Borg               backup',
    'Encryption         serverside secret messages',
    'Themes             custom themes',
    'Glossary           custom glossary',
    'Jubilee            monthly points creation event',
    'Back to Main Menu'
  ]
  const answer = await inquirer.prompt({
    name: 'features_menu',
    type: 'list',
    message: 'Please choose:',
    choices: features,
    pageSize: features.length
  })
  switch(answer.features_menu) {
    case 'Back to Main Menu':
      return false
    default:
      console.log("Not yet implemented")
      return true
  }
  return true
}

// Ask the user for their name and returns it
async function askName() {
  const answer = await inquirer.prompt({
    name: 'member_name',
    type: 'input',
    message: 'What username would you like?'
  })
  return answer.member_name
}

// Prints the given todoItems (array of strings) and allows items to be checked and unchecked
async function todoList(title, todoItems) {
    console.log(`\n${headerStyle(title)}`)
  const answer = await inquirer.prompt({
    name: 'todo_list',
    type: 'checkbox',
    message: 'Check or uncheck items with Spacebar:',
    choices: todoItems
  })
}

// Detects which version(s) of the AO are installed (ao-3, ao-react, or ao-v)
function detectAoVersion() {
  
}

// Main entry point
async function main() {
  // No root allowed (todo)
  exitIfRoot()
  
  // Loading screen, display some quick info during the fun animation
  distro = detectOS()
  if(checkAoEnvFile()) {
    console.log('AO .env file exists at', AO_ENV_FILE_PATH)
  } else {
    console.log('AO .env file does not exist at', AO_ENV_FILE_PATH)
  }
  await unicornPortal(650)
  
  // Main AO title screen and flavor text
  clearScreen()
  asciiArt()
  await welcome()
  
  // Main loop
  while(await mainMenu()) {}
  process.exit(0)
}

await main()