import express from 'express';
import bodyParser from 'body-parser';
import compression from 'compression';
import contentFilter from 'content-filter';
import helmet from 'helmet';
import cors from 'cors';
import api from './api';
import db from './db';
import Mail from './helpers/mail';


// tell if server is running in debug or production environment
console.info(process.env.NODE_ENV === 'production' ?
  '===== PRODUCTION =====' : process.env.NODE_ENV === 'test' ? '' :'===== DEVELOPMENT =====');


// mongodb connection
db.connect();

// mail service
Mail.init();

// create Express app
const app = express();

// get port from environment, defaults to 3000
const port = process.env.PORT || 3000;

// security headers
const defaultHeaderConfig = {
  contentSecurityPolicy: {
    directives: {
      defaultSrc: [`'none'`],
      baseUri: [`'self'`],
      formAction: [`'none'`],
      frameAncestors: [`'none'`]
    }
  },
  frameguard: {
    action: 'deny'
  },
  permittedCrossDomainPolicies: true,
  refererPolicy: true
};
app.use(helmet(defaultHeaderConfig));
// special CSP header for api-doc
app.use('/api-doc', helmet.contentSecurityPolicy({
  ...defaultHeaderConfig,
  directives: {
    defaultSrc: [`'none'`],
    scriptSrc: [`'self'`],
    connectSrc: [`'self'`],
    styleSrc: [`'self'`, `'unsafe-inline'`],
    imgSrc: [`'self'`, 'data:']
  }
}));
// special CSP header for the intro-presentation
app.use(/\/static\/intro-presentation\/(index.html)?/, helmet.contentSecurityPolicy({
  ...defaultHeaderConfig,
  directives: {
    defaultSrc: [`'none'`],
    scriptSrc: [`'self'`, `'unsafe-inline'`],
    styleSrc: [`'self'`, `'unsafe-inline'`],
    imgSrc: [`'self'`]
  }
}));
// special CSP header for the bosch-logo.svg
app.use('/static/*.svg', helmet.contentSecurityPolicy({
  ...defaultHeaderConfig,
  directives: {
    styleSrc: [`'unsafe-inline'`]
  }
}));

// middleware
app.use(compression());  // compress responses
app.use(express.json({ limit: '5mb'}));
app.use(express.urlencoded({ extended: false, limit: '5mb' }));
app.use(bodyParser.json());
app.use(contentFilter({
  urlBlackList: ['$', '&&', '||'],
  bodyBlackList: ['$', '{', '&&', '||'],
  appendFound: true
}));  // filter URL query attacks
app.use((err, req, res, ignore) => {  // bodyParser error handling
  res.status(400).send({status: 'Invalid JSON body'});
});
app.use((req, res, next) => {  // no database connection error
  if (db.getState().db) {
    next();
  }
  else {
    console.error('No database connection');
    res.status(500).send({status: 'Internal server error'});
  }
});
app.use(cors());  // CORS headers
app.use(require('./helpers/authorize'));  // handle authentication

// redirect /api routes for Angular proxy in development
if (process.env.NODE_ENV !== 'production') {
  app.use('/api/:url([^]+)', (req, res) => {
    req.url = '/' + req.params.url;
    app.handle(req, res);
  });
}


// require routes
app.use('/', require('./routes/root'));
app.use('/', require('./routes/sample'));
app.use('/', require('./routes/material'));
app.use('/', require('./routes/measurement'));
app.use('/', require('./routes/template'));
app.use('/', require('./routes/model'));
app.use('/', require('./routes/user'));

// static files
app.use('/static', express.static('static'));

// Swagger UI
app.use('/api-doc', api());

app.use((req, res) => {  // 404 error handling
  res.status(404).json({status: 'Not found'});
});

app.use((err, req, res, ignore) => {  // internal server error handling
  console.error(err);
  res.status(500).json({status: 'Internal server error'});
});


// hook up server to port
const server = app.listen(port, () => {
  console.info(process.env.NODE_ENV === 'test' ? '' : `Listening on http://localhost:${port}`);
});

module.exports = server;