const express = require('express');
const bcrypt = require('bcrypt');
var authRouter = express.Router();
const models = require('../models/index.js');
const chkLogin = require('../middleware/auth.js');
const loginRateLimit = require('../middleware/loginRateLimit.js');
var resp = require('../response.js');

const regenerateSession = (req) => {
    return new Promise((resolve, reject) => {
        req.session.regenerate((err) => {
            if (err) {
                return reject(err);
            }
            resolve();
        });
    });
};

const destroySession = (req) => {
    return new Promise((resolve, reject) => {
        req.session.destroy((err) => {
            if (err) {
                return reject(err);
            }
            resolve();
        });
    });
};

authRouter.post("/register", chkLogin, loginRateLimit, async (req, res) => {
    try {
        const { fname, mname, lname, gender, username, email, phone } = req.body;
        const { password } = req.body;

        if (!fname || !lname || !username || !password || !email || !phone || !gender) {
            return res.status(400).json(resp("Register Error", "All required fields must be provided", null, req, false));
        }

        const saltRounds = 10;
        const hashedPassword = await bcrypt.hash(password, saltRounds);

        const data = { fname, mname, lname, gender, username, email, phone, password: hashedPassword, status: 'pending' };
        const result = await new models.User().createUser(data);

        return res.json(
            resp(
                "User Created",
                "User details registered successfully",
                result,
                req
            )
        );

    } catch (err) {
        console.error(err);
        return res.status(500).json(
            resp(
                "Error",
                "Error registering User",
                null,
                req
            )
        );
    }
});

authRouter.post("/login", loginRateLimit, async (req, res) => {
    try {
        const { username, password } = req.body;

        if (!username || !password) {
            return res.status(400).json(resp("Login Error", "Username and password are required", null, req, false));
        }

        const user = await models.User.findOne({
            where: { username },
            attributes: ["id", "fname", "password", "status"]
        });

        if (!user) {
            return res.status(401).json(resp("Login Error", "Incorrect Username or Password", null, req, false));
        }

        const validPassword = await bcrypt.compare(password, user.password);
        if (!validPassword) {
            return res.status(401).json(resp("Login Error", "Incorrect Username or Password", null, req, false));
        }

        if (String(user.status).toLowerCase() !== "active") {
            return res.status(403).json(resp("Login Error", "User account is not active", null, req, false));
        }

        const userProfile = await models.User.findByPk(user.id, {
            attributes: ["id", "fname"],
            include: [
                {
                    model: models.Group,
                    attributes: ["id", "name"],
                    through: { attributes: [] },
                    include: [
                        {
                            model: models.Module,
                            attributes: ["id", "name"],
                            through: { attributes: ["create", "read", "update", "delete"] }
                        }
                    ]
                },
                {
                    model: models.Entity,
                    attributes: ["id", "name"],
                    through: { attributes: [] }
                }
            ]
        });

        const acl = (userProfile?.Groups || []).flatMap(group => group.Modules || []);

        await regenerateSession(req);

        req.session.loggedIn = true;
        req.session.userId = user.id;
        req.session.name = user.fname;
        req.session.userAcl = acl;
        req.session.userGroups = (userProfile?.Groups || []).map((group) => group?.name).filter(Boolean);
        req.session.entities = userProfile?.Entities || [];
        loginRateLimit.clearForRequest(req);

        return res.json(resp("Login Success", "User Logged In successfully", "No data returned", req));

    } catch (err) {
        console.error(err);
        return res.status(500).json(resp("Login Error", "Unable to Login", null, req, false));
    }
});

authRouter.post("/logout", chkLogin, async (req, res) => {
    try {
        await destroySession(req);
        res.clearCookie('sessionId');
        return res.json(
            resp(
                "Logout Success",
                "User logged out successfully",
                "No data returned",
                req
            )
        );
    } catch (err) {
        console.error(err);
        return res.status(500).json(resp("Logout Error", "Unable to logout", null, req, false));
    }
});

authRouter.get("/checklogin", chkLogin, (req, res) => {
    res.send(
        resp(
            "Success",
            "Your Login session is Active",
            "User is Logged In",
            req
        )
    )
});

module.exports = authRouter;