text: const express = require('express')
  const google = require('googleapis').google
  const youtube = google.youtube({ version: 'v3' })
  const OAuth2 = google.auth.OAuth2
  const state = require('./state.js')
  const fs = require('fs')
  
  async function robot() {
      console.log('> [youtube-robot] Starting...')
      const content = state.load()
  
      await authenticateWithOAuth()
      const videoInformation = await uploadVideo(content)
      await uploadThumbnail(videoInformation)
  
      async function authenticateWithOAuth() {
          const webServer = await startWebServer()
          const OAuthClient = await createOAuthClient()
          requestUserConsent(OAuthClient)
          const authorizationToken = await waitForGoogleCallback(webServer)
          await requestGoogleForAccessTokens(OAuthClient, authorizationToken)
          await setGlobalGoogleAuthentication(OAuthClient)
          await stopWebServer(webServer)
  
          async function startWebServer() {
              return new Promise((resolve, reject) => {
                  const port = 5000
                  const app = express()
  
                  const server = app.listen(port, () => {
                      console.log(`> [youtube-robot] Listening on http://localhost:${port}`)
  
                      resolve({
                          app,
                          server
                      })
                  })
              })
          }
  
          async function createOAuthClient() {
              const credentials = require('../credentials/google-youtube.json')
  
              const OAuthClient = new OAuth2(
                  credentials.web.client_id,
                  credentials.web.client_secret,
                  credentials.web.redirect_uris[0]
              )
  
              return OAuthClient
          }
  
          function requestUserConsent(OAuthClient) {
              const consentUrl = OAuthClient.generateAuthUrl({
                  acess_type: 'offline',
                  scope: ['https://www.googleapis.com/auth/youtube']
              })
  
              console.log(`> [youtube-robot] Please give your consent: ${consentUrl}`)
          }
  
          async function waitForGoogleCallback(webServer) {
              return new Promise((resolve, reject) => {
                  console.log(`> [youtube-robot] Waiting for user consent...`)
  
                  webServer.app.get('/oauth2callback', (req, res) => {
                      const authCode = req.query.code
                      console.log(`> [youtube-robot] Consent given: ${authCode}`)
  
                      res.send('<h1>Thank you!</h1><p>Now close this tab.</p>')
                      resolve(authCode)
                  })
              })
          }
  
          async function requestGoogleForAccessTokens(OAuthClient, authorizationToken) {
              return new Promise((resolve, reject) => {
                  OAuthClient.getToken(authorizationToken, (err, tokens) => {
                      if (err) {
                          return reject(err)
                      }
  
                      console.log('> [youtube-robot] Access tokens received!')
  
                      OAuthClient.setCredentials(tokens)
                      resolve()
                  })
              })
          }
  
          async function setGlobalGoogleAuthentication(OAuthClient) {
              google.options({
                  auth: OAuthClient
              })
          }
  
          async function stopWebServer(webServer) {
              return new Promise((resolve, reject) => {
                  webServer.server.close(() => {
                      resolve()
                  })
              })
          }
      }
  
      async function uploadVideo(content) {
          const videoFilePath = './content/video-maker.mp4'
          const videoFileSize = fs.statSync(videoFilePath).size
          const videoTitle = `${content.prefix} ${content.searchTerm}`
          const videoTags = [content.searchTerm, ...content.sentences[0].keywords]
          const videoDescription = content.sentences.map((sentence) => {
              return sentence.text
          }).join('\n\n')
  
          const requestParameters = {
              part: 'snippet, status',
              requestBody: {
                  snippet: {
                      title: videoTitle,
                      description: videoDescription,
                      tags: videoTags
                  },
                  status: {
                      privacyStatus: 'unlisted'
                  }
              },
              media: {
                  body: fs.createReadStream(videoFilePath)
              }
          }
  
          console.log('> [youtube-robot] Starting to upload the video to YouTube')
          const youtubeResponse = await youtube.videos.insert(requestParameters, {
              onUploadProgress: onUploadProgress
          })
  
          console.log(`> [youtube-robot] Video available at: https://youtu.be/${youtubeResponse.data.id}`)
          return youtubeResponse.data
  
          function onUploadProgress(event) {
              const progress = Math.round((event.bytesRead / videoFileSize) * 100)
              console.log(`> [youtube-robot] ${progress}% completed`)
          }
      }
  
      async function uploadThumbnail(videoInformation) {
          const videoId = videoInformation.id
          const videoThumbnailFilePath = './content/youtube-thumbnail.jpg'
  
          const requestParameters = {
              videoId: videoId,
              media: {
                  mimeType: 'image/jpeg',
                  body: fs.createReadStream(videoThumbnailFilePath)
              }
          }
  
          const youtubeResponse = await youtube.thumbnails.set(requestParameters)
          console.log(`> [youtube-robot] Thumbnail uploaded!`)
      }
  }
  
  module.exports = robot