import { app, BrowserWindow, Menu, ipcMain, screen } from 'electron'
import Datastore from 'nedb'

if (process.argv.includes('--version')) {
  console.log(`v${app.getVersion()}`)
  app.exit(0)
} else {
  runApp()
}

function runApp() {
  require('@electron/remote/main').initialize()

  require('electron-context-menu')({
    showSearchWithGoogle: false,
    showSaveImageAs: true,
    showCopyImageAddress: true,
    prepend: (params, browserWindow) => []
  })

  const localDataStorage = app.getPath('userData') // Grabs the userdata directory based on the user's OS

  const settingsDb = new Datastore({
    filename: localDataStorage + '/settings.db',
    autoload: true
  })

  // disable electron warning
  process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'
  const path = require('path')
  const isDev = process.env.NODE_ENV === 'development'
  const isDebug = process.argv.includes('--debug')
  let mainWindow
  let openedWindows = []
  let startupUrl

  // CORS somehow gets re-enabled in Electron v9.0.4
  // This line disables it.
  // This line can possible be removed if the issue is fixed upstream
  app.commandLine.appendSwitch('disable-features', 'OutOfBlinkCors')

  app.commandLine.appendSwitch('enable-accelerated-video-decode')
  app.commandLine.appendSwitch('enable-file-cookies')
  app.commandLine.appendSwitch('ignore-gpu-blacklist')

  // See: https://stackoverflow.com/questions/45570589/electron-protocol-handler-not-working-on-windows
  // remove so we can register each time as we run the app.
  app.removeAsDefaultProtocolClient('freetube')

  // If we are running a non-packaged version of the app && on windows
  if (isDev && process.platform === 'win32') {
    // Set the path of electron.exe and your app.
    // These two additional parameters are only available on windows.
    app.setAsDefaultProtocolClient('freetube', process.execPath, [path.resolve(process.argv[1])])
  } else {
    app.setAsDefaultProtocolClient('freetube')
  }

  // TODO: Uncomment if needed
  // only allow single instance of application
  if (!isDev) {
    const gotTheLock = app.requestSingleInstanceLock()

    if (gotTheLock) {
      app.on('second-instance', (event, commandLine, workingDirectory) => {
        // Someone tried to run a second instance, we should focus our window.
        if (mainWindow && typeof (commandLine) !== 'undefined') {
          if (mainWindow.isMinimized()) mainWindow.restore()
          mainWindow.focus()

          const url = getLinkUrl(commandLine)
          if (url) {
            mainWindow.webContents.send('openUrl', url)
          }
        }
      })

      app.on('ready', (event, commandLine, workingDirectory) => {
        settingsDb.find({
          $or: [
            { _id: 'disableSmoothScrolling' },
            { _id: 'useProxy' },
            { _id: 'proxyProtocol' },
            { _id: 'proxyHostname' },
            { _id: 'proxyPort' }
          ]
        }, function (err, doc) {
          if (err) {
            app.exit(0)
            return
          }

          let disableSmoothScrolling = false
          let useProxy = false
          let proxyProtocol = 'socks5'
          let proxyHostname = '127.0.0.1'
          let proxyPort = '9050'

          if (typeof doc === 'object' && doc.length > 0) {
            doc.forEach((dbItem) => {
              switch (dbItem._id) {
                case 'disableSmoothScrolling':
                  disableSmoothScrolling = dbItem.value
                  break
                case 'useProxy':
                  useProxy = dbItem.value
                  break
                case 'proxyProtocol':
                  proxyProtocol = dbItem.value
                  break
                case 'proxyHostname':
                  proxyHostname = dbItem.value
                  break
                case 'proxyPort':
                  proxyPort = dbItem.value
                  break
              }
            })
          }

          if (disableSmoothScrolling) {
            app.commandLine.appendSwitch('disable-smooth-scrolling')
          } else {
            app.commandLine.appendSwitch('enable-smooth-scrolling')
          }

          const proxyUrl = `${proxyProtocol}://${proxyHostname}:${proxyPort}`

          createWindow(useProxy, proxyUrl)

          if (isDev) {
            installDevTools()
          }

          if (isDebug) {
            mainWindow.webContents.openDevTools()
          }
        })
      })
    } else {
      app.quit()
    }
  } else {
    require('electron-debug')({
      showDevTools: !(process.env.RENDERER_REMOTE_DEBUGGING === 'true')
    })

    app.on('ready', () => {
      settingsDb.find({
        $or: [
          { _id: 'disableSmoothScrolling' },
          { _id: 'useProxy' },
          { _id: 'proxyProtocol' },
          { _id: 'proxyHostname' },
          { _id: 'proxyPort' }
        ]
      }, function (err, doc) {
        if (err) {
          app.exit(0)
          return
        }

        let disableSmoothScrolling = false
        let useProxy = false
        let proxyProtocol = 'socks5'
        let proxyHostname = '127.0.0.1'
        let proxyPort = '9050'

        if (typeof doc === 'object' && doc.length > 0) {
          doc.forEach((dbItem) => {
            switch (dbItem._id) {
              case 'disableSmoothScrolling':
                disableSmoothScrolling = dbItem.value
                break
              case 'useProxy':
                useProxy = dbItem.value
                break
              case 'proxyProtocol':
                proxyProtocol = dbItem.value
                break
              case 'proxyHostname':
                proxyHostname = dbItem.value
                break
              case 'proxyPort':
                proxyPort = dbItem.value
                break
            }
          })
        }

        if (disableSmoothScrolling) {
          app.commandLine.appendSwitch('disable-smooth-scrolling')
        } else {
          app.commandLine.appendSwitch('enable-smooth-scrolling')
        }

        const proxyUrl = `${proxyProtocol}://${proxyHostname}:${proxyPort}`

        createWindow(useProxy, proxyUrl)

        if (isDev) {
          installDevTools()
        }

        if (isDebug) {
          mainWindow.webContents.openDevTools()
        }
      })
    })
  }

  async function installDevTools () {
    try {
      /* eslint-disable */
      require('vue-devtools').install()
      /* eslint-enable */
    } catch (err) {
      console.log(err)
    }
  }

  function createWindow (useProxy = false, proxyUrl = '', replaceMainWindow = true) {
    /**
     * Initial window options
     */
    const newWindow = new BrowserWindow({
      backgroundColor: '#fff',
      icon: isDev
        ? path.join(__dirname, '../../_icons/iconColor.png')
        /* eslint-disable-next-line */
        : `${__dirname}/_icons/iconColor.png`,
      autoHideMenuBar: true,
      // useContentSize: true,
      webPreferences: {
        nodeIntegration: true,
        nodeIntegrationInWorker: false,
        webSecurity: false,
        backgroundThrottling: false,
        enableRemoteModule: true,
        contextIsolation: false
      },
      show: false
    })
    openedWindows.push(newWindow)
    if (replaceMainWindow) {
      mainWindow = newWindow
    }

    newWindow.setBounds({
      width: 1200,
      height: 800
    })

    if (useProxy) {
      newWindow.webContents.session.setProxy({
        proxyRules: proxyUrl
      })
    }

    // Set CONSENT cookie on reasonable domains
    [
      'http://www.youtube.com',
      'https://www.youtube.com',
      'http://youtube.com',
      'https://youtube.com'
    ].forEach(url => {
      newWindow.webContents.session.cookies.set({
        url: url,
        name: 'CONSENT',
        value: 'YES+'
      })
    })

    settingsDb.findOne({
      _id: 'bounds'
    }, function (err, doc) {
      if (doc === null || err) {
        return
      }

      if (typeof doc !== 'object' || typeof doc.value !== 'object') {
        return
      }

      const { maximized, ...bounds } = doc.value
      const allDisplaysSummaryWidth = screen
        .getAllDisplays()
        .reduce((accumulator, { size: { width } }) => accumulator + width, 0)

      if (allDisplaysSummaryWidth >= bounds.x) {
        newWindow.setBounds({
          x: bounds.x,
          y: bounds.y,
          width: bounds.width,
          height: bounds.height
        })
      }
      if (maximized) {
        newWindow.maximize()
      }
    })

    // If called multiple times
    // Duplicate menu items will be added
    if (replaceMainWindow) {
      // eslint-disable-next-line
      setMenu()
    }

    // load root file/url
    if (isDev) {
      newWindow.loadURL('http://localhost:9080')
    } else {
      /* eslint-disable-next-line */
      newWindow.loadFile(`${__dirname}/index.html`)

      global.__static = path
        .join(__dirname, '/static')
        .replace(/\\/g, '\\\\')
    }

    // Show when loaded
    newWindow.on('ready-to-show', () => {
      newWindow.show()
      newWindow.focus()
    })

    newWindow.on('close', () => {
      // Clear cache and storage if it's the last window
      if (openedWindows.length === 1) {
        newWindow.webContents.session.clearCache()
        newWindow.webContents.session.clearStorageData({
          storages: [
            'appcache',
            'cookies',
            'filesystem',
            'indexdb',
            'shadercache',
            'websql',
            'serviceworkers',
            'cachestorage'
          ]
        })
      }
    })

    newWindow.on('closed', () => {
      // Remove closed window
      openedWindows = openedWindows.filter((window) => window !== newWindow)
      if (newWindow === mainWindow) {
        // Replace mainWindow to avoid accessing `mainWindow.webContents`
        // Which raises "Object has been destroyed" error
        mainWindow = openedWindows[0]
      }

      console.log('closed')
    })
  }

  // Save closing window bounds & maximized status
  ipcMain.on('setBounds', (_e, data) => {
    const value = {
      ...mainWindow.getNormalBounds(),
      maximized: mainWindow.isMaximized()
    }

    settingsDb.findOne({
      _id: 'bounds'
    }, function (err, doc) {
      if (err) {
        return
      }
      if (doc !== null) {
        settingsDb.update({
          _id: 'bounds'
        }, {
          $set: {
            value
          }
        }, {})
      } else {
        settingsDb.insert({
          _id: 'bounds',
          value
        })
      }
    })
  })

  ipcMain.on('appReady', () => {
    if (startupUrl) {
      mainWindow.webContents.send('openUrl', startupUrl)
    }
  })

  ipcMain.on('disableSmoothScrolling', () => {
    app.commandLine.appendSwitch('disable-smooth-scrolling')
    mainWindow.close()
    createWindow()
  })

  ipcMain.on('enableSmoothScrolling', () => {
    app.commandLine.appendSwitch('enable-smooth-scrolling')
    mainWindow.close()
    createWindow()
  })

  ipcMain.on('enableProxy', (event, url) => {
    console.log(url)
    mainWindow.webContents.session.setProxy({
      proxyRules: url
    })
  })

  ipcMain.on('disableProxy', () => {
    mainWindow.webContents.session.setProxy({})
  })

  ipcMain.on('createNewWindow', () => {
    createWindow(false, '', false)
  })

  app.on('window-all-closed', () => {
    if (process.platform !== 'darwin') {
      app.quit()
    }
  })

  app.on('activate', () => {
    if (mainWindow === null || mainWindow === undefined) {
      createWindow()
    }
  })

  /*
   * Callback when processing a freetube:// link (macOS)
   */
  app.on('open-url', (event, url) => {
    event.preventDefault()

    if (mainWindow && mainWindow.webContents) {
      mainWindow.webContents.send('openUrl', baseUrl(url))
    } else {
      startupUrl = baseUrl(url)
    }
  })

  /*
   * Check if an argument was passed and send it over to the GUI (Linux / Windows).
   * Remove freetube:// protocol if present
   */
  const url = getLinkUrl(process.argv)
  if (url) {
    startupUrl = url
  }

  function baseUrl(arg) {
    return arg.replace('freetube://', '')
  }

  function getLinkUrl(argv) {
    if (argv.length > 1) {
      return baseUrl(argv[argv.length - 1])
    } else {
      return null
    }
  }

  /**
   * Auto Updater
   *
   * Uncomment the following code below and install `electron-updater` to
   * support auto updating. Code Signing with a valid certificate is required.
   * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
   */

  /*
  import { autoUpdater } from 'electron-updater'
  autoUpdater.on('update-downloaded', () => {
    autoUpdater.quitAndInstall()
  })

  app.on('ready', () => {
    if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
  })
   */

  /* eslint-disable-next-line */
  const sendMenuEvent = async data => {
    mainWindow.webContents.send('change-view', data)
  }

  const template = [{
    label: 'File',
    submenu: [
      {
        role: 'quit'
      }
    ]
  },
  {
    label: 'Edit',
    submenu: [{
      role: 'cut'
    },
    {
      role: 'copy',
      accelerator: 'CmdOrCtrl+C',
      selector: 'copy:'
    },
    {
      role: 'paste',
      accelerator: 'CmdOrCtrl+V',
      selector: 'paste:'
    },
    {
      role: 'pasteandmatchstyle'
    },
    {
      role: 'delete'
    },
    {
      role: 'selectall'
    }
    ]
  },
  {
    label: 'View',
    submenu: [{
      role: 'reload'
    },
    {
      role: 'forcereload',
      accelerator: 'CmdOrCtrl+Shift+R'
    },
    {
      role: 'toggledevtools'
    },
    {
      type: 'separator'
    },
    {
      role: 'resetzoom'
    },
    {
      role: 'zoomin'
    },
    {
      role: 'zoomout'
    },
    {
      type: 'separator'
    },
    {
      role: 'togglefullscreen'
    }
    ]
  },
  {
    role: 'window',
    submenu: [{
      role: 'minimize'
    },
    {
      role: 'close'
    }
    ]
  }
  ]

  function setMenu () {
    if (process.platform === 'darwin') {
      template.unshift({
        label: app.getName(),
        submenu: [
          { role: 'about' },
          { type: 'separator' },
          { role: 'services' },
          { type: 'separator' },
          { role: 'hide' },
          { role: 'hideothers' },
          { role: 'unhide' },
          { type: 'separator' },
          { role: 'quit' }
        ]
      })

      template.push({
        role: 'window'
      })

      template.push({
        role: 'help'
      })

      template.push({ role: 'services' })
    }

    const menu = Menu.buildFromTemplate(template)
    Menu.setApplicationMenu(menu)
  }
}
