#!/usr/bin/env node --unhandled-rejections=strict

var config = require('./config')
if (config.get('newrelic_license_key')) {
  require('newrelic')
}

var debug = require('debug')('p3api-server:app')
var express = require('express')
var path = require('path')
var logger = require('morgan')
var cookieParser = require('cookie-parser')
var hpiSearchRouter = require('./routes/hpiSearch')
var dataTypeRouter = require('./routes/dataType')
var downloadRouter = require('./routes/download')
var multiQueryRouter = require('./routes/multiQuery')
var contentRouter = require('./routes/content')
var rpcHandler = require('./routes/rpcHandler')
var jbrowseRouter = require('./routes/JBrowse')
var genomePermissionRouter = require('./routes/genomePermissionRouter')
var indexer = require('./routes/indexer')
var cors = require('cors')

process.on('uncaughtException', (err, origin) => {
  console.log(`Uncaught Expcetion. [${(new Date()).toISOString()}] ${err}, ${origin}`)
})
process.on('unhandledRejection', (reason, promise) => {
  console.log(`UnhandledRejection. [${(new Date()).toISOString()}] reason: ${reason}, promise:`, promise)
})

var app = module.exports = express()
app.listen(config.get('http_port') || 3001)

// view engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')

app.enable('etag')
app.set('etag', 'strong')

var stats = null

logger.token('qtime', function (req, res) {
  var from = 'QUERY '
  if (req.cacheHit) {
    from = 'CACHE '
  }

  if (!res.formatStart || !res.queryStart) {
    return ''
  }

  return from + (res.formatStart.valueOf() - res.queryStart.valueOf())
})
logger.token('remote-ip', function (req, res) {
  return req.headers['x-forwarded-for'] || req.connection.remoteAddress
})

app.use(logger('[:date[iso]] :remote-ip :method :url :status :response-time [:qtime] ms - :res[content-length]'))

app.use(function (req, res, next) {
  debug('APP MODE: ', app.get('env'))
  req.production = (app.get('env') === 'production')
  next()
})

app.use(cookieParser())

app.use(cors({
  origin: true,
  methods: ['GET,POST,PUT,DELETE'],
  allowHeaders: ['if-none-match', 'range', 'accept', 'x-range', 'content-type', 'authorization'],
  exposedHeaders: ['facet_counts', 'x-facet-count', 'Content-Range', 'X-Content-Range', 'ETag'],
  credential: true,
  maxAge: 8200
}))

var collections = config.get('collections')

app.use('/indexer', indexer)

app.post('/', rpcHandler)

app.use('/health', function (req, res, next) {
  res.write('OK')
  res.end()
})

app.use('/stats', function (req, res, next) {
  if (stats) {
    res.write(JSON.stringify(stats))
  } else {
    res.write('{}')
  }
  res.end()
})

app.use('/content', [
  contentRouter
])

app.use('/testTimeout', function (req, res, next) {
  setTimeout(function () {
    res.send('OK')
    res.end()
  }, 60 * 1000 * 5)
})

app.use('/jbrowse/', [
  jbrowseRouter
])

app.use('/query', [
  multiQueryRouter
])

app.use('/hpi/search', [
  hpiSearchRouter
])

app.param('dataType', function (req, res, next, dataType) {
  if (collections.indexOf(dataType) !== -1) {
    next()
    return
  }
  next('route')
})

app.use('/bundle/:dataType/', [
  downloadRouter
])

app.use('/permissions/genome', [
  genomePermissionRouter
])

app.use('/:dataType/', [
  dataTypeRouter
])

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  var err = new Error('Not Found')
  err.status = 404
  next(err)
})

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function (err, req, res, next) {
    debug('Dev env error handler: err status', err.status)
    res.status(err.status || 500)
    res.render('error', {
      message: err.message,
      error: err
    })
  })
}

// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
  debug('Dev env error handler: ', ' err status', err.status)
  res.status(err.status || 500)
  res.render('error', {
    message: err.message,
    error: {}
  })
})

@@ -3293,46 +3293,16 @@
 %0A// 
-catch 404 and forward to error handler
+Send 404
 %0Aapp
@@ -3340,613 +3340,193 @@
 %7B%0A  
-var err = new Error('Not Found')%0A  err.status = 404%0A  next(err)%0A%7D)%0A%0A// error handlers%0A%0A// development error handler%0A// will print stacktrace%0Aif (app.get('env') === 'development') %7B%0A  app.use(function (err, req, res, next) %7B%0A    debug('Dev env error handler: err status', err.status)%0A    res.status(err.status %7C%7C 500)%0A  
+console.error(%60Unable to find router.%60, req)%0A  res.setHeader('Content-Type', 'application/json')%0A  res.status(404)%0A
   res.
-render('error', %7B%0A      message: err.message,%0A      error: err%0A    %7D)%0A  %7D)%0A%7D%0A%0A// production error handler%0A// no stacktraces leaked to user%0Aapp.use(function (err, req, res, next) %7B%0A  debug('Dev env error handler: ', ' err status', err.status)%0A  res.status(err.status %7C%7C 500
+send(%7B%0A    'status': 404,%0A    'message': 'Not Found'%0A  %7D
 )%0A  res.
 rend
@@ -3525,70 +3525,12 @@
 res.
-r
 end
-er('error', %7B%0A    message: err.message,%0A    error: %7B%7D%0A  %7D
+(
 )%0A%7D)
-%0A

set default error in application/json format