import express from 'express';
import { DB_NAME, getDatabaseClient } from '../db-utils';
import bcrypt from 'bcrypt';
import { generateJWT, SALT_ROUNDS } from './auth';
import sendGridMail, { MailDataRequired } from '@sendgrid/mail';

const authRoutes = express.Router();

authRoutes.post('/register/', async (request, response) => {
    const name: string = request.body.name;
    const email: string = request.body.email;
    const password: string = request.body.password;
    const isVerified: boolean = false;
    
    const userCollection = getDatabaseClient().db(DB_NAME).collection('users');
    
    // Check if form is filled
    if (!name || !email || !password) {
        response.status(400);
        response.send("Please field the required fields");
        return;
    }

    try {
        const userWithSameMail = await userCollection.find({
            email,
        }).count();

        if (userWithSameMail > 0) {
            response.status(400);
            response.send('EmailID already exists');
            return;
        }

    } catch {
        return;
    }

    try {
        bcrypt.hash(password, SALT_ROUNDS, (error, hashedPassword) => {
            if (error) {
                throw error;
            }
    
            userCollection.insertOne({
                name,
                email,
                password: hashedPassword,
                isVerified,
            });
        });

        response.send("Registeration Complete, Please verify your profile to proceed further");
    } catch {
        return;
    }

    return;

});


authRoutes.post('/request-verification/', async (request, response) => {
    const email: string = request.body.email;

    if (!email) {
        response.status(400);
        response.send("Missing Email ID");
    }

    const userCollection = getDatabaseClient().db(DB_NAME).collection('users');

    let users = await userCollection.find({
        email,
    }).toArray();

    const matchedUser = users[0];

    if (!matchedUser) {
        response.status(400);
        response.send('No user under this EmailID');
        return;
    } else if (matchedUser.isVerified) {
        response.status(400);
        response.send('The user is already verified');
        return;
    }

    const otp = 1000 + Math.ceil(Math.random() * 8999);

    const otpMail: MailDataRequired = {
        to: email,
        from: 'nikhilkj24@gmail.com',
        subject: 'Webtrigon Job-portal Sign Up Verification',
        text: `Please use the OTP ${otp} to verify your Email ID`,
    };

    await userCollection.updateOne({
        _id: matchedUser._id,
    }, {
        $set: {
            otp: otp,
        }
    });

    sendGridMail.send(otpMail).then(data=> {
        response.send('Verification OTP sent');
        return;
    }, () => {
        response.sendStatus(500);
        response.send("SMTP system failure");
        return;
    });

    return;
});


authRoutes.post('/verify-user/', async (request, response) => {
    const email: string = request.body.email;
    const otp: number = Number(request.body.otp);

    if (!email || !otp) {
        response.status(400);
        response.send("Please fill in the required fields");
    }

    const userCollection = getDatabaseClient().db(DB_NAME).collection('users');

    let users = await userCollection.find({
        email,
    }).toArray();

    const matchedUser = users[0];

    if (!matchedUser) {
        response.status(400);
        response.send('No user under this EmailID');
        return;
    } else if (matchedUser.isVerified) {
        response.status(400);
        response.send('The user is already verified');
        return;
    }

    if (matchedUser.otp === otp) {
        response.status(200);
        response.send("User Verified");
    } else {
        response.status(400);
        response.send('Verification failed, please try again.');
        return;
    }

    await userCollection.updateOne({
        email: matchedUser.email,
    }, {
        $set: {
            isVerified: true,
        }
    });

    return;
});

authRoutes.post('/api-auth/', async (request, response) => {
    const email: string = request.body.email;
    const password: string = request.body.password;

    if (!email || !password) {
        response.status(400);
        response.send("Please field the required fields");
        return;
    }

    const userCollection = getDatabaseClient().db(DB_NAME).collection('users');

    let users = await userCollection.find({
        email,
    }).toArray();

    const matchedUser = users[0];

    if (!matchedUser) {
        response.status(400);
        response.send('Wrong credentials');
        return;
    } else if (!matchedUser.isVerified) {
        response.status(400);
        response.send('Please complete user verification');
        return;
    }

    let passwordComparisonResult: boolean;

    try {
        passwordComparisonResult = await bcrypt.compare(password, matchedUser.password);

        if (passwordComparisonResult) {
            response.send({
                id: matchedUser._id,
                token: generateJWT(matchedUser._id),
            });
        } else {
            response.status(400);
            response.send('Wrong credentials');
        }

    } catch(e) {
        response.sendStatus(500);
        response.json(e);
    }

    return;
});

export default authRoutes;