text: 'use strict'
  
  const {
    app,
    BrowserWindow,
    Menu,
    shell,
    dialog,
    ipcMain,
    nativeTheme,
    Notification,
    Tray
  } = require('electron')
  const debug = require('electron-debug')
  const { ensureDirSync } = require('fs-extra')
  const portfinder = require('portfinder')
  const { once } = require('events')
  const { promises: fs } = require('fs')
  const { promisify } = require('util')
  const chmodr = require('chmodr')
  const Store = require('electron-store')
  const { autoUpdater } = require('electron-updater')
  const log = require('electron-log')
  const express = require('express')
  const { version: p2pcommons } = require('@p2pcommons/sdk-js/package.json')
  
  debug({ isEnabled: true, showDevTools: false })
  app.allowRendererProcessReuse = false
  process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = true
  const isMac = process.platform === 'darwin'
  
  require('@electron/remote/main').initialize()
  
  let mainWindow
  let tray = null
  const store = new Store()
  const p2pcommonsDir = `${app.getPath('home')}/.p2pcommons${
    !app.isPackaged ? '-dev' : ''
  }`
  
  function sleep (ms) {
    return new Promise(resolve => {
      setTimeout(resolve, ms)
    })
  }
  
  const p2pcommonsLocal = express()
  p2pcommonsLocal.use(express.static(p2pcommonsDir))
  portfinder.getPort(function (err, port) {
    if (err) throw err
  
    p2pcommonsLocal.listen(port)
    store.set('staticServerPort', port)
  })
  
  log.transports.file.level = 'debug'
  log.transports.ipc.level = 'debug'
  autoUpdater.logger = log
  
  ipcMain.handle('getStoreValue', (_, key, defaultValue) =>
    store.get(key, defaultValue)
  )
  ipcMain.handle('setStoreValue', (_, key, value) => store.set(key, value))
  ;[
    'vault',
    'showWelcome',
    'tour',
    'analytics',
    'chatra',
    'keyBackedUp',
    'lastInstalledAppVersion',
    'showTerms'
  ].forEach(key => {
    store.onDidChange(
      key,
      value => mainWindow && mainWindow.webContents.send(key, value)
    )
  })
  
  ipcMain.handle('dragOut', (_, value) => {
    _.sender.startDrag({
      file: value,
      icon: './build/noun_Hand_43997.png'
    })
  })
  
  ipcMain.handle('copyPrivateKey', async (_, value) => {
    const { filePath } = await dialog.showSaveDialog(mainWindow, {
      defaultPath: 'hypergraph-key.zip'
    })
    if (!filePath) return
  
    await mainWindow.webContents.send('export key', filePath)
    await sleep(5000)
    return true
  })
  
  if (app.getVersion() !== store.get('lastInstalledAppVersion')) {
    // Welcome + Terms + (!)keyBackedup = Show terms after update
    // !Welcome + !Terms + (!)keyBackedUp = Show nothing after update
    // Welcome + !Terms + !keyBackedup = Force back up through welcome screen
    // !Welcome + (!)Terms + !keyBackedup = Notification to back up key
    store.set('showWelcome', true)
    store.set('showTerms', true)
    store.set('keyBackedUp', false)
  }
  
  const updateMenu = () => {
    const isVaultEnabled = store.get('vault', false)
    Menu.setApplicationMenu(
      Menu.buildFromTemplate([
        ...(isMac ? [{ role: 'appMenu' }] : []),
        {
          role: 'fileMenu',
          submenu: [
            {
              label: 'Add content',
              accelerator: 'CmdOrCtrl+N',
              click: () => {
                mainWindow.webContents.send('goto-create')
              }
            }
          ]
        },
        { role: 'editMenu' },
        { role: 'viewMenu' },
        {
          label: 'Database',
          submenu: [
            {
              label: 'Back up database',
              click: async () => {
                const { filePath } = await dialog.showSaveDialog(mainWindow, {
                  defaultPath: 'hypergraph-key.zip'
                })
                if (!filePath) return
  
                mainWindow.webContents.send('export key', filePath)
              }
            },
            {
              label: 'Export module graph',
              click: async () => {
                const { filePath } = await dialog.showSaveDialog(mainWindow, {
                  defaultPath: 'p2pcommons.json'
                })
                if (!filePath) return
  
                mainWindow.webContents.send('export graph')
                const [, graph] = await once(ipcMain, 'export graph')
                await fs.writeFile(filePath, JSON.stringify(graph, null, 2))
              }
            }
          ]
        },
        { role: 'windowMenu' },
        {
          role: 'help',
          submenu: [
            {
              label: 'About',
              click: () => {
                dialog.showMessageBox({
                  message: `Running version ${app.getVersion()} of ${app.getName()}\nPowered by version ${p2pcommons} of the p2pcommons`,
                  type: 'info'
                })
              }
            },
            {
              label: 'Reopen welcome screens',
              click: () => store.set('showWelcome', true)
            },
            {
              label: 'Reopen tour',
              click: () => store.set('tour', true)
            },
            {
              label: 'Credits',
              click: () =>
                shell.openExternal(
                  'https://github.com/hypergraph-xyz/desktop/blob/gh-pages/credits.md'
                )
            },
            {
              label: 'Learn More',
              click: () => shell.openExternal('https://hypergraph.xyz')
            },
            {
              label: 'Membership Area',
              click: () => shell.openExternal('https://gov.libscie.org')
            },
            {
              label: 'Terms',
              click: () =>
                shell.openExternal(
                  'https://www.notion.so/libscie/Terms-Hypergraph-2794527482b54eddb5b7c991e8152999'
                )
            }
          ]
        },
        ...(!app.isPackaged
          ? [
            {
              label: 'Devtools',
              submenu: [
                {
                  label: 'Reset database',
                  click: async () => {
                    const { response } = await dialog.showMessageBox(
                      mainWindow,
                      {
                        type: 'warning',
                        buttons: ['Reset database', 'Cancel'],
                        message:
                            'Are you sure you want to reset your p2pcommons database? This will delete your profile and content from your computer and cannot be undone.'
                      }
                    )
                    if (response === 1) return
  
                    await mainWindow.webContents.send('reset database')
                    await store.clear()
                  }
                },
                {
                  label: `${isVaultEnabled ? 'Disable' : 'Enable'} Vault`,
                  click: async () => {
                    if (!isVaultEnabled) {
                      const { response } = await dialog.showMessageBox(
                        mainWindow,
                        {
                          type: 'warning',
                          buttons: ['Enable Vault', 'Cancel'],
                          message:
                              'Are you sure you want to enable the Hypergraph Vault? This will add all existing content to it, to be stored indefinitely.'
                        }
                      )
                      if (response === 1) return
                    }
                    store.set('vault', !isVaultEnabled)
                    updateMenu()
                  }
                }
              ]
            }
          ]
          : [])
      ])
    )
  }
  store.onDidChange('vault', updateMenu)
  
  const createMainWindow = async () => {
    const win = new BrowserWindow({
      title: app.name,
      show: false,
      width: 1440,
      height: 920,
      minWidth: 820,
      minHeight: 764,
      webPreferences: {
        nodeIntegration: true,
        enableRemoteModule: true,
        contextIsolation: false
      },
      titleBarStyle: 'hiddenInset'
    })
    updateMenu()
  
    win.on('ready-to-show', () => win.show())
    win.on('closed', () => (mainWindow = undefined))
    if (!app.isPackaged && !process.env.CI) win.webContents.openDevTools()
    if (app.isPackaged) {
      await win.loadFile('build/index.html')
    } else {
      await win.loadURL('http://localhost:1212/dist/index.html')
    }
    return win
  }
  
  if (!app.requestSingleInstanceLock()) app.quit()
  
  app.on('second-instance', (_, argv) => {
    if (!mainWindow) return
    if (mainWindow.isMinimized()) mainWindow.restore()
    mainWindow.show()
    const lastArg = argv[argv.length - 1]
    if (/^p2pcommons:\/\//.test(lastArg)) {
      const url = lastArg.replace(/\/$/, '')
      mainWindow.webContents.send('open', url)
    }
  })
  app.on('open-url', async (ev, url) => {
    ev.preventDefault()
    if (!mainWindow) mainWindow = await createMainWindow()
    mainWindow.webContents.send('open', url)
  })
  app.on('window-all-closed', () => {
    if (process.platform !== 'darwin' || process.env.CI) {
      app.quit()
    }
  })
  app.on('activate', async () => {
    if (!mainWindow) mainWindow = await createMainWindow()
  })
  
  const getTrayImagePath = () => {
    const returnPath = isMac
      ? `${__dirname}/build/tray/icon-mac@4x.png`
      : `${__dirname}/build/tray/icon-windows.png`
  
    return returnPath
  }
  
  const updateTray = () => {
    if (!tray) return
  
    tray.setImage(getTrayImagePath())
    const template = [
      {
        label: `Open ${app.getName()}`,
        click: function () {
          mainWindow.show()
        }
      },
      {
        label: 'Quit',
        click: function () {
          app.isQuiting = true
          app.quit()
        }
      }
    ]
  
    const menu = Menu.buildFromTemplate(template)
    tray.setContextMenu(menu)
  }
  
  const main = async () => {
    ensureDirSync(p2pcommonsDir)
    // ensure chmod +rw for p2pcommonsdir
    await promisify(chmodr)(p2pcommonsDir, 0o666)
    await app.whenReady()
  
    tray = new Tray(getTrayImagePath())
    tray.setToolTip(`${app.getName()} v${app.getVersion()}`)
    updateTray()
  
    mainWindow = await createMainWindow()
    app.setAsDefaultProtocolClient('p2pcommons')
    if (app.isPackaged) autoUpdater.checkForUpdatesAndNotify()
    if (!store.get('keyBackedUp') && store.get('showWelcome') === false) {
      const backUpKey = new Notification({
        title: 'Create new backup',
        body:
          'Ensure you keep access to your account: Create a new backup by clicking here.'
      })
      backUpKey.show()
      backUpKey.on('click', async () => {
        const { filePath } = await dialog.showSaveDialog(mainWindow, {
          defaultPath: 'hypergraph-key.zip'
        })
        if (!filePath) return
  
        mainWindow.webContents.send('export key', filePath)
      })
    }
  
    mainWindow.on('minimize', function (event) {
      event.preventDefault()
      mainWindow.hide()
    })
  
    mainWindow.on('close', function (event) {
      if (!app.isQuiting) {
        event.preventDefault()
        mainWindow.hide()
      }
  
      return false
    })
  
    tray.on('click', async () => {
      if (!isMac) mainWindow.show()
    })
  }
  nativeTheme.on('updated', updateTray)
  main()
  