const os = require(`os`)
const path = require(`path`)
const Store = require(`./store`)
const fetch = require(`node-fetch`)
const Configstore = require(`configstore`)
const { ensureDirSync } = require(`fs-extra`)

const isTruthy = require(`./is-truthy`)

/* The events data collection is a spooled process that
 * buffers events to a local fs based buffer
 * which then is asynchronously flushed to the server.
 * This both increases the fault tolerancy and allows collection
 * to continue even when working offline.
 */
module.exports = class EventStorage {
  analyticsApi =
    process.env.GATSBY_TELEMETRY_API || `https://analytics.gatsbyjs.com/events`
  constructor() {
    try {
      this.config = new Configstore(`gatsby`, {}, { globalConfigPath: true })
    } catch (e) {
      // This should never happen
      this.config = {
        get: key => this.config[key],
        set: (key, value) => (this.config[key] = value),
        all: this.config,
        path: path.join(os.tmpdir(), `gatsby`),
        "telemetry.enabled": true,
        "telemetry.machineId": `not-a-machine-id`,
      }
    }

    const baseDir = path.dirname(this.config.path)

    try {
      ensureDirSync(baseDir)
    } catch (e) {
      // TODO: Log this event
    }

    this.store = new Store(baseDir)
    this.verbose = isTruthy(process.env.GATSBY_TELEMETRY_VERBOSE)
    this.debugEvents = isTruthy(process.env.GATSBY_TELEMETRY_DEBUG)
    this.disabled = isTruthy(process.env.GATSBY_TELEMETRY_DISABLED)
  }

  isTrackingDisabled() {
    return this.disabled
  }

  addEvent(event) {
    if (this.disabled) {
      return
    }

    const eventString = JSON.stringify(event)

    if (this.debugEvents || this.verbose) {
      console.error(`Captured event:`, JSON.parse(eventString))

      if (this.debugEvents) {
        // Bail because we don't want to send debug events
        return
      }
    }

    this.store.appendToBuffer(eventString + `\n`)
  }

  async sendEvents() {
    return this.store.startFlushEvents(async eventsData => {
      const events = eventsData
        .split(`\n`)
        .filter(e => e && e.length > 2) // drop empty lines
        .map(e => JSON.parse(e))

      return this.submitEvents(events)
    })
  }

  async submitEvents(events) {
    try {
      const res = await fetch(this.analyticsApi, {
        method: `POST`,
        headers: { "content-type": `application/json` },
        body: JSON.stringify(events),
      })
      return res.ok
    } catch (e) {
      return false
    }
  }

  getConfig(key) {
    if (key) {
      return this.config.get(key)
    }
    return this.config.all
  }

  updateConfig(key, value) {
    return this.config.set(key, value)
  }
}

@@ -2354,16 +2354,26 @@
 aders: %7B
+%0A         
  %22conten
@@ -2399,16 +2399,70 @@
 on/json%60
+,%0A          %22user-agent%22: this.getUserAgent(),%0A       
  %7D,%0A    
@@ -2572,16 +2572,199 @@
  %7D%0A  %7D%0A%0A
+  getUserAgent() %7B%0A    try %7B%0A      const %7B name, version %7D = require(%60../package.json%60)%0A      return %60$%7Bname%7D:$%7Bversion%7D%60%0A    %7D catch (e) %7B%0A      return %60Gatsby Telemetry%60%0A    %7D%0A  %7D%0A%0A
   getCon

Set custom user agent for telemetry fetch (#17906)