/*
*				libreevent - routes.js
*
*	Created by Janis Hutz 07/11/2023, Licensed under the GPL V3 License
*			https://janishutz.com, development@janishutz.com
*
*
*/

const db = require( './db/db.js' );
const pwdmanager = require( './credentials/pwdmanager.js' );
const auth = require( './credentials/2fa.js' );
const twoFA = new auth();
const path = require( 'path' );
const mail = require( './mail/mailSender.js' );
const mailManager = new mail();
const bodyParser = require( 'body-parser' );
const generator = require( './token.js' );

let responseObjects = {};
let authOk = {};
let mailTokens = {};

module.exports = ( app, settings ) => {
    app.get( '/user/details', ( request, response ) => {
        if ( request.session.loggedInUser ) {
            db.getDataSimple( 'users', 'email', request.session.username ).then( data => {
                if ( data[ 0 ] ) {
                    let dat = {};
                    for ( let element in data[ 0 ] ) {
                        if ( element !== 'pass' ) {
                            dat[ element ] = data[ 0 ][ element ];
                        }
                    }
                    response.send( { 'data': dat, 'status': true } );
                } else {
                    response.status( 404 ).send( { 'data': 'This user does not exist', 'status': false } );
                }
            } ).catch( () => {
                console.log( 'dbError' );
                response.status( 500 ).send( { 'data': 'There was an error reading data from the database. If this error persists, please contact the administrators', 'status': false } );
            } );
        } else {
            response.status( 403 ).sendFile( path.join( __dirname + '/../ui/en/errors/403.html' ) );
        }
    } );

    app.get( '/test/user', ( req, res ) => {
        req.session.loggedInUser = true;
        req.session.username = 'info@janishutz.com';
        res.send( 'ok' );
    } );

    app.post( '/user/login', bodyParser.json(), ( request, response ) => {
        if ( request.body.mail && request.body.password ) {
            pwdmanager.checkpassword( request.body.mail, request.body.password ).then( data => {
                if ( data.status ) {
                    request.session.username = request.body.mail;
                    if ( data.twoFA === 'simple' ) {
                        ( async () => {
                            let tok = twoFA.registerStandardAuthentication()[ 'token' ];
                            let ipRetrieved = request.headers[ 'x-forwarded-for' ];
                            let ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : request.connection.remoteAddress;
                            mailManager.sendMail( request.body.mail, await twoFA.generateTwoFAMail( tok, ip, settings.yourDomain, settings.name ), 'Verify login', settings.mailSender );
                            request.session.token = tok;
                            response.send( { 'status': '2fa' } );
                        } )();
                    } else if ( data.twoFA === 'enhanced' ) {
                        ( async () => {
                            let res = twoFA.registerEnhancedAuthentication();
                            let ipRetrieved = request.headers[ 'x-forwarded-for' ];
                            let ip = ipRetrieved ? ipRetrieved.split( /, / )[ 0 ] : request.connection.remoteAddress;
                            mailManager.sendMail( request.body.mail, await twoFA.generateTwoFAMail( res.token, ip, settings.yourDomain, settings.name ), 'Verify login', settings.mailSender );
                            request.session.token = res.token;
                            response.send( { 'status': '2fa+', 'code': res.code } );
                        } )();
                    } else {
                        request.session.loggedInUser = true;
                        response.send( { 'status': 'ok' } );
                    }
                } else {
                    response.send( { 'status': 'pwErr' } );
                }
            } );
        } else {
            response.status( 400 ).send( 'missingCredentials' );
        }
    } );

    app.get( '/user/2fa', ( request, response ) => {
        let tokType = twoFA.verifySimple( request.query.token );
        if ( tokType === 'standard' ) {
            request.session.loggedInUser = true;
            if ( responseObjects[ request.query.token ] ) {
                responseObjects[ request.query.token ].write( 'data: authenticated\n\n' );
            } else {
                authOk[ request.query.token ] = 'ok';
            }
            response.sendFile( path.join( __dirname + '/../ui/en/2fa/2faSimple.html' ) );
        } else if ( tokType === 'enhanced' ) {
            response.sendFile( path.join( __dirname + '/../ui/en/2fa/2faEnhanced.html' ) );
        } else {
            response.status( 403 ).sendFile( path.join( __dirname + '/../ui/en/2fa/2faInvalid.html' ) );
        }
    } );

    app.post( '/user/2fa/verify', bodyParser.json(), ( request, response ) => {
        let verified = twoFA.verifyEnhanced( request.body.token, request.body.code );
        if ( verified ) {
            request.session.loggedInUser = true;
            if ( responseObjects[ request.body.token ] ) {
                responseObjects[ request.body.token ].write( 'data: authenticated\n\n' );
                responseObjects[ request.body.token ].end();
                delete responseObjects[ request.body.token ];
            } else {
                authOk[ request.body.token ] = 'ok';
            }
            response.send( 'ok' );
        } else response.status( 403 ).send( 'wrong' );
    } );

    app.get( '/user/2fa/check', ( request, response ) => {
        response.writeHead( 200, {
            'Content-Type': 'text/event-stream',
            'Cache-Control': 'no-cache',
            'Connection': 'keep-alive',
        } );
        response.status( 200 );
        response.flushHeaders();
        response.write( 'data: connected\n\n' );
        responseObjects[ request.session.token ] = response;
    } );

    app.get( '/user/2fa/ping', ( request, response ) => {
        if ( authOk[ request.session.token ] === 'ok' ) {
            delete authOk[ request.session.token ];
            response.send( { 'status': 'ok' } );
        } else {
            response.send( '' );
        }
    } );

    app.get( '/user/logout', ( request, response ) => {
        request.session.loggedInUser = false;
        request.session.username = '';
        response.send( 'logoutOk' );
    } );

    app.get( '/user/resendEmail', ( req, res ) => {
        if ( req.session.username ) {
            ( async () => {
                let tok = generator.generateToken( 60 );
                mailTokens[ tok ] = req.session.username;
                mailManager.sendMail( req.session.username, await twoFA.generateSignupEmail( tok, settings.yourDomain, settings.name ), 'Confirm your email', settings.mailSender );
            } )();
            res.send( 'sent' );
        } else {
            res.status( 403 ).send( 'unauthorised' );
        }
    } );

    app.post( '/user/signup', bodyParser.json(), ( request, response ) => {
        if ( request.body.password && request.body.password === request.body.password2 && request.body.firstName && request.body.name && request.body.country && request.body.mail ) {
            db.checkDataAvailability( 'users', 'email', request.body.mail ).then( status => {
                if ( status ) {
                    response.send( 'exists' );
                } else {
                    ( async () => {
                        let tok = generator.generateToken( 60 );
                        mailTokens[ tok ] = request.body.mail;
                        mailManager.sendMail( request.body.mail, await twoFA.generateSignupEmail( tok, settings.yourDomain, settings.name ), 'Confirm your email', settings.mailSender );
                    } )();
                    pwdmanager.hashPassword( request.body.password ).then( hash => {
                        db.writeDataSimple( 'users', 'email', request.body.mail, { 
                            'email': request.body.mail, 
                            'pass': hash, 
                            'first_name': request.body.firstName, 
                            'name': request.body.name, 
                            'two_fa': 'disabled', 
                            'user_data': JSON.stringify( { 'country': request.body.country } ), 
                            'marketing': request.body.newsletter ? generator.generateToken( 60 ) : null 
                        } ).then( () => {
                            request.session.loggedInUser = true;
                            request.session.username = request.body.mail;
                            response.send( 'ok' );
                        } );
                    } );
                }
            } );
        } else {
            response.status( 400 ).send( 'incomplete' );
        }
    } );

    app.get( '/user/signup/confirm', ( request, response ) => {
        if ( Object.keys( mailTokens ).includes( request.query.token ) ) {
            request.session.username = mailTokens[ request.query.token ];
            db.writeDataSimple( 'users', 'email', request.session.username, { 'mail_confirmed': 'true' } );
            delete mailTokens[ request.query.token ];
            if ( settings.twoFA === 'allow' ) {
                response.sendFile( path.join( __dirname + '/../ui/en/signup/allowTwoFA.html' ) );
            } else if ( settings.twoFA === 'enforce' ) {
                response.sendFile( path.join( __dirname + '/../ui/en/signup/enforceTwoFA.html' ) );
            } else {
                response.sendFile( path.join( __dirname + '/../ui/en/signup/disallowTwoFA.html' ) );
            }
        } else {
            response.status( 400 ).sendFile( path.join( __dirname + '/../ui/en/signup/invalid.html' ) );
        }
    } );
    
    app.post( '/user/settings/:setting', bodyParser.json(), ( request, response ) => {
        let call = request.params.setting;
        if ( request.session.username ) {
            if ( call === '2fa' ) {
                db.writeDataSimple( 'users', 'email', request.session.username, { 'two_fa': request.body.twoFA } );
                response.send( 'ok' );
            }
        } else {
            response.status( 403 ).send( 'unauthorised' );
        }
    } );

    app.post( '/user/settings', bodyParser.json(), ( req, res ) => {
        if ( req.session.username ) {
            db.writeDataSimple( 'users', 'email', req.session.username, req.body );
            res.send( 'ok' );
        } else {
            res.status( 403 ).send( 'unauthorised' );
        }
    } );
    
    app.get( '/settings/2fa', ( request, response ) => {
        response.send( settings.twoFA );
    } );
};