const Debug = require('debug')
const electronApp = require('./lib/util/electron-app')
const { telemetry, OTLPTraceExporterCloud } = require('@packages/telemetry')
const { apiRoutes } = require('./lib/cloud/routes')
const encryption = require('./lib/cloud/encryption')
const { override: overrideTty } = require('./lib/util/tty')
const { GracefulExit } = require('./lib/util/graceful-exit')
const { NetProfiler } = require('./lib/util/net_profiler')

const { calculateCypressInternalEnv, configureLongStackTraces } = require('./lib/environment')

const debug = Debug('cypress:server:start-cypress')

process.env['CYPRESS_INTERNAL_ENV'] = calculateCypressInternalEnv()
configureLongStackTraces(process.env['CYPRESS_INTERNAL_ENV'])
process.env['CYPRESS'] = 'true'

// are we in the main node process or the electron process?
const isRunningElectron = electronApp.isRunning()

const pkg = require('@packages/root')

if (isRunningElectron) {
  // if we are in the electron process, we need to patch the electron switches before Cypress launches the app
  // @see https://www.electronjs.org/docs/latest/api/environment-variables#electron_run_as_node
  const { app } = require('electron')
  const { appendElectronSwitches } = require('./lib/append_electron_switches')

  appendElectronSwitches(app)

  // To pass unencrypted telemetry data to an independent open telemetry endpoint,
  // disable the encryption header, update the url, and add any other required headers.
  // For example:
  // const exporter = new OTLPTraceExporterCloud({
  //   url: 'https://api.honeycomb.io/v1/traces',
  //   headers: {
  //     'x-honeycomb-team': 'key',
  //   },
  // })
  // See additional information here: https://github.com/cypress-io/cypress/blob/develop/packages/telemetry/README.md#otlptraceexportercloud
  const exporter = new OTLPTraceExporterCloud({
    url: apiRoutes.telemetry(),
    encryption,
  })

  telemetry.init({
    namespace: 'cypress:server',
    version: pkg.version,
    exporter,
  })

  const { debugElapsedTime } = require('./lib/util/performance_benchmark')

  const v8SnapshotStartupTime = debugElapsedTime('v8-snapshot-startup-time')
  const endTime = v8SnapshotStartupTime + global.cypressServerStartTime

  telemetry.startSpan({ name: 'cypress', attachType: 'root', active: true, opts: { startTime: global.cypressBinaryStartTime } })

  GracefulExit.addStep(async (code) => {
    try {
      const span = telemetry.getSpan('cypress')

      span?.setAttribute('exitCode', code)
      span?.end()
    } catch (error) {
      debug('Error during cleanup of telemetry span on exit: %o', error)
    } finally {
      await telemetry.shutdown()
    }
  }, 'finalize telemetry')

  const v8SnapshotSpan = telemetry.startSpan({ name: 'v8snapshot:startup', opts: { startTime: global.cypressServerStartTime } })

  v8SnapshotSpan?.end(endTime)

  telemetry.startSpan({ name: 'binary:startup' })
}

const { patchFs } = require('./lib/util/patch-fs')
const fs = require('fs')

// prevent EMFILE errors
patchFs(fs)

// override tty if we're being forced to
overrideTty()

if (process.env.CY_NET_PROFILE && isRunningElectron) {
  const netProfiler = new NetProfiler()

  process.stdout.write(`Network profiler writing to ${netProfiler.logPath}\n`)
}

require('./lib/unhandled_exceptions').handle()

process.env.UV_THREADPOOL_SIZE = 128

if (isRunningElectron) {
  require('./lib/util/process_profiler').start()
}

// warn when deprecated callback apis are used in electron
// https://github.com/electron/electron/blob/master/docs/api/process.md#processenablepromiseapis
process.enablePromiseAPIs = process.env.CYPRESS_INTERNAL_ENV !== 'production'

// don't show any electron deprecation warnings in prod
process.noDeprecation = process.env.CYPRESS_INTERNAL_ENV === 'production'

// always show stack traces for Electron deprecation warnings
process.traceDeprecation = true

require('./lib/util/suppress_warnings').suppress()

module.exports = require('./lib/cypress').start(process.argv)
