require('dotenv').config({path: '././.env'});
const logger = require('../../logger');
const passport = require('passport');
var express = require('express'),
    bodyParser = require('body-parser'),
    cookieParser = require('cookie-parser'),
    session = require('express-session'),
    crypto = require("crypto"),
    methodOverride = require('method-override'),
    cors = require('cors');
    errorHandler = require('errorhandler'),
    helmet = require('helmet'),
    requestIp = require('request-ip'),
    SkinStore = require('connect-mongoskin'),
    expose = require('express-expose')
    router = require('./router'),
    semusiConfig = require('./config'),
    formData = require("express-form-data");
var app = express();
    app = expose(app);
    app.engine('html', require('ejs').renderFile);
    app.set('views', __dirname + '/views');
    app.set('view engine', 'html');
    app.set('view options', {layout:false});
    app.set('trust proxy', true );
    app.use(formData.parse('connect-multiparty'));
    app.use(formData.format());
    app.use(formData.union());
    app.use(express.json());
    app.use(express.urlencoded());
    app.use(cookieParser());
    app.use((req, res, next) => {
        res.locals.nonce = crypto.randomBytes(16).toString("hex");
        next();
      });
    

    app.use(function (req, res, next) {
        res.setHeader(
          'Content-Security-Policy',
          `default-src 'self'; font-src 'self' ${semusiConfig.fontsrc}; img-src 'self' blob: data: ${semusiConfig.imagesrc}  ${semusiConfig.appListSrc}; script-src 'self' 'nonce-${res.locals.nonce}' 'unsafe-inline' 'strict-dynamic' https: http:; style-src 'self' 'unsafe-inline' ${semusiConfig.stylesrc}; frame-src 'self' ${semusiConfig.framesrc} ; object-src 'none'; base-uri 'self';connect-src 'self' ${semusiConfig.connectsrc}; media-src 'self' ${semusiConfig.videosrc} ${semusiConfig.appListSrc};`
        );
        next();
    });
    app.use(helmet.hidePoweredBy());
    app.use(helmet.frameguard());
    app.use(helmet.noSniff());
    app.use(
    helmet.hsts({
       maxAge: 315569520000,   //max age is The time, in seconds, that the browser should remember that a site is only to be accessed using HTTPS (10years)
       includeSubDomains: true, 
        preload: true 
    })
    );
    app.use(helmet.referrerPolicy({ policy: 'no-referrer' })); // Referrer policy
    app.use(helmet.permittedCrossDomainPolicies()); // Controls cross-domain policies

    app.use(cors({
        origin: semusiConfig.accessContolAllowOrigin
      }));

    app.use(session({
        secret:'countlyss',
        store:new SkinStore(semusiDb),
        cookie  : { secure:true , maxAge  : semusiConfig.sessionAge, sameSite:'Lax' }
    }));
    // Initialize Passport
    app.use(passport.initialize());
    app.use(passport.session());

    app.use(require('connect-flash')());
    app.use(function(req, res, next) {
        res.locals.flash = req.flash.bind(req);
        next();
    });  
    app.use(methodOverride());
    app.use(express.static(__dirname + '/public'));
    app.use(errorHandler());

    // Restrict HTTP Methods
    app.use((req, res, next) => {
      const allowedMethods = ['GET', 'POST'];
      if (!allowedMethods.includes(req.method)) {
          return res.sendStatus(405); // Method Not Allowed
      }
      next();
    });

        // Add Custom Security Headers Middleware
    app.use((req,res,next) =>{
      // Cross-Origin Resource Policy (CORP)
        res.setHeader('Cross-Origin-Resource-Policy', 'same-site');
        // Ensures that resources are only shared with the same origin
        res.setHeader('Cross-Origin-Resource-Policy', 'same-origin');
    
        // Cross-Origin Opener Policy (COOP)
        // Prevents cross-origin interactions by isolating your site
        res.setHeader('Cross-Origin-Opener-Policy', 'same-origin');
        // Cross-Origin Embedder Policy (COEP)
        // Requires cross-origin resources to grant permission before being embedded
        res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp');
    
        // Permission Policy header
        // Controls access to various browser features and APIs
        res.setHeader('Permission-Policy',
          'geolocation=(self), ' +              // Restrict location access to your origin
          'microphone=(), ' +                  // Disallow microphone access
          'camera=(), ' +                      // Disallow camera access
          'fullscreen=(self), ' +              // Restrict fullscreen requests to your origin
          'payment=(self), ' +                 // Restrict Payment API to your origin
          'push=(self), ' +                    // Restrict Push API to your origin
          'clipboard-write=(), ' +             // Disallow clipboard write access
          'accelerometer=(), ' +               // Disallow accelerometer access
          'ambient-light-sensor=(), ' +        // Disallow ambient light sensor access
          'magnetometer=(), ' +                // Disallow magnetometer access
          'gyroscope=(), ' +                   // Disallow gyroscope access
          'usb=()'                             // Disallow WebUSB API access
        );
        logs(req,res);
        next();
    })
 
    app.use('/', router);
    app.use(function (err, req, res, next) {
        if (err.status !== 403) return next(err);
        res.status(200)
        res.render("globalError")
    });
    app.use((err, req, res, next) => {
        // Check for error status code between 400 and 506
        if (err.status >= 400 && err.status <= 505) {
          // Render custom error page
          res.status(200).render('globalError');
        } else {
          // Pass the error to the default Express error handler
          next(err);
        }
      });
    app.use(function(req, res) {
        res.status(404).render('globalError')
    })
    app.listen(semusiConfig.web.port, semusiConfig.web.host  || '');
    function logs(req,res){
        if(req.session.uid){
            semusiDb.collection('members').findOne({ "_id": semusiDb.ObjectID(req.session.uid) }, function (err, member) {
                if(!err){
                    let email = member.email;
                    email = email.split('');
                    let finalArr=[];
                    let len = email.indexOf('@');
                    email.forEach((item,pos)=>{
                    (pos>=1 && pos<=len-2) ? finalArr.push('*') : finalArr.push(email[pos]);
                    })
                    const bytesAtBeginningOfRequest = req.socket.bytesWritten || 0;
                    let bytesWritten = 0;
                    let bytesServed = 0;
                    req.socket.on("drain", function() {
                    bytesWritten += req.socket.bytesWritten;
                    });
                    res.on("finish", function() {
                      bytesServed = bytesWritten - bytesAtBeginningOfRequest;
                    logger.info({
                        hostname :req.headers.host,
                        userAgent: req.headers['user-agent'],
                        PATH :req.url,
                        URL: req.originalUrl,
                        response_status : res.statusCode,
                        user_id: finalArr.join(''),
                        response: req.body,
                        bytes_served: bytesServed,
                        server_address:semusiConfig.web.host,
                        memberId: member.api_key,
                        client_IP: requestIp.getClientIp(req),
            
                    })  
                });

                }
    
           })
         }
     }
