/**
 * @file authController.js
 * @author Radim Buráň (xburan03@stud.fit.vutbr.cz)
 */

const jwt = require("jsonwebtoken");
const bcrypt = require("bcrypt");
const service = require('../services/usersServices');
const utility = require('../utility');
const {sendEmail} = require("../services/emailService");

const COOKIE_MAX_AGE = 1800000; //30m

function sendToken(req, res, userID) {
    const token = jwt.sign({ "id": userID }, process.env.SECRET_TOKEN,{ expiresIn: "30m" });
    return res.status(201)
        .cookie('usertoken', token, {
            maxAge: COOKIE_MAX_AGE,
            httpOnly: true,
            signed: true
        })
        .json({ token: token});
}

const register = async (req, res) => {
    const data = req.body;
    if (!['email', 'name', 'password', 'passwordConfirm'].every((p) => data.hasOwnProperty(p) && data.p !== null)) {
        return res.status(400).json({error: "Fill all required fields"});
    }

    if (data.password !== data.passwordConfirm) {
        return res.status(403).json({error: "Passwords do not match"});
    }
    delete data.passwordConfirm;
    const salt = await bcrypt.genSalt(13);
    data.password = await bcrypt.hash(data.password, salt);

    let user = await service.create(data);
    if (user && user.error === undefined) {
        sendEmail(user.email, "Flowerpot - Registrace", "Úspěšná registrace!");
        return await sendToken(req, res, user.id);
    }
    else {
        if (user.error === undefined) {
            return res.status(400).json({msg: "Something wrong"});
        }
        res.status(500);
        return res.json({error: user.error});
    }
}

const login = async (req, res) => {
    const data = req.body;

    if (!['email', 'password'].every((p) => data.hasOwnProperty(p) && data.p !== null)) {
        return res.status(400).json({error: "Fill all required fields"});
    }

    const user = (await service.getByFilter({ email: data.email})).items[0];

    if (user) {
        const match = await bcrypt.compare(data.password, user.password);
        if (!match) {
            return res.status(400).json({error: "Bad password"});
        }
        return await sendToken(req, res, user.id);
    } else {
        res.status(404).json({error: "Bad email"});
    }
}

const logout = async (req, res) => {
    return res.status(202).clearCookie('usertoken').json({msg: "logout"});
}

const changePassword = async (req, res) => {
    const data = req.body;

    const userID = req?.user?.id;
    if (userID === undefined || userID === null) {
        return res.status(404).json({error: "No user in request"});
    }

    if (!["password", "newPassword", "confirmPassword"].every((p) => data.hasOwnProperty(p) && data.p !== null)) {
        return res.status(400).json({error: "Fill all required fields"});
    }

    if (data.newPassword !== data.confirmPassword) {
        return res.status(403).json({error: "Passwords do not match"});
    }

    const user = (await service.getByFilter({ id: userID})).items[0];
    if (user) {
        const match = await bcrypt.compare(data.password, user.password);
        if (!match) {
            return res.status(400).json({error: "Bad current password"});
        }
    } else {
        res.status(500).json({error: "Something went wrong!"});
    }

    const salt = await bcrypt.genSalt(13);
    const newPwd = await bcrypt.hash(data.newPassword, salt);
    const changedUser = await service.update({ id: userID, password: newPwd});

    sendEmail(user.email, "Flowerpot - Změna hesla", "Heslo úspěšně změněno!");

    return logout(req, res);
}

const changeEmail = async (req, res) => {
    const data = req.body;

    const userID = req?.user?.id;
    if (userID === undefined || userID === null) {
        return res.status(404).json({error: "No user in request"});
    }

    if (!["password", "email", "newEmail", "confirmEmail"].every((p) => data.hasOwnProperty(p) && data.p !== null)) {
        return res.status(400).json({error: "Fill all required fields"});
    }

    if (data.newEmail !== data.confirmEmail) {
        return res.status(403).json({error: "Emails do not match"});
    }

    const user = (await service.getByFilter({ id: userID})).items[0];
    if (user) {
        const match = await bcrypt.compare(data.password, user.password);
        if (!match) {
            return res.status(400).json({error: "Bad password"});
        }
        if (data.email !== user.email) {
            return res.status(403).json({error: "Bad current email"});
        }
    } else {
        res.status(500).json({error: "Something went wrong!"});
    }

    const changedUser = await service.update({ id: userID, email: data.newEmail});

    return logout(req, res);
}


module.exports = {
    register,
    login,
    logout,
    changePassword,
    changeEmail
}