const express = require('express');
const { v4: uuidv4 } = require('uuid');

const {schemas} = require("../models/schemaMapper");
const {httpStatus} = require("../helpers/httpResponses");
const crypto = require("crypto");
const {departmentsDB} = require("../db/jsonDatabaseManager");

const router = express.Router();

function validateBody(req, res, next) {
    if(req.path !== '/login'){
        const ceoDB = req.app.get('ceoDB');
        const ceoPassword = req.headers['ceo_password'];
        const {password} = ceoDB.readFile()

        if(ceoPassword !== password){
            return res.status(httpStatus.UNAUTHORIZED).json({message: 'Invalid CEO password.'});
        }
    }

    let validationSchema = undefined;

    switch(req.path){
        case '/set_security_levels':
            validationSchema = schemas.securityLevelsModelSchema;
            break;
        case '/login':
            validationSchema = schemas.usersLoginModelSchema;
            break;
        case '/departments':
            validationSchema = schemas.departmentRegisterModelSchema;
            break;
        case '/':
            if(req.method === 'PUT'){
                validationSchema = schemas.ceoModifyModelSchema;
            }
            break;
        default:
            validationSchema = undefined;
    }

    if(validationSchema !== undefined){
        const {error} = validationSchema.validate(req.body);
        if(error){
            const errorMessage = error.details.map(detail => detail.message).join(', ');
            return res.status(httpStatus.BAD_REQUEST).json({ message: errorMessage });
        }
    }

    next();
}

router.post('/login', validateBody, (req, res) => {
    const ceoDB = req.app.get('ceoDB');
    const { email, password } = req.body;

    if(ceoDB.findIndexByKeyValueInArray('email', email) !== ceoDB.findIndexByKeyValueInArray('password', password)){
        return res.status(httpStatus.UNAUTHORIZED).json({message: 'Invalid credentials.'});
    }

    return res.status(httpStatus.OK).json({message: 'Logged in.', data: ceoDB.readFile()});
});

router.post('/set_security_levels', validateBody, (req, res) => {
    const departmentsDB = req.app.get('departmentsDB');
    const departmentsJson = departmentsDB.readFile();

    const levelsJson = req.body;
    console.log(levelsJson);

    const newJson = {};

    Object.entries(levelsJson).forEach(([levelKey, departmentName]) => {
        let departmentId = -1;
        for (let deptKey in departmentsJson) {
            if (departmentsJson.hasOwnProperty(deptKey)) {
                if (departmentsJson[deptKey].name === departmentName) {
                    departmentId = deptKey;
                    break;
                }
            }
        }

        if (departmentId !== -1) {
            newJson[levelKey] = {
                name: departmentName,
                key: departmentsJson[departmentId].key
            };
        }
    });


    departmentsDB.writeFile(newJson);
    return res.status(httpStatus.OK).json({message: 'Departments levels updated.'});
});

router.delete('/users/:id', validateBody, (req, res) => {
    const usersDB = req.app.get('usersDB');
    const { id } = req.params;

    let usersJson = usersDB.readFile();

    const userIndex = usersJson.findIndex(user => user.id === id);
    if (userIndex === -1) {
        return res.status(httpStatus.NOT_FOUND).json({message: 'User not found in system.'});
    }

    usersJson.splice(userIndex, 1);


    usersDB.writeFile(usersJson);

    return res.status(httpStatus.OK).json({ message: 'User deleted successfully.' });
});

router.post('/departments', validateBody, (req, res) => {
    const departmentsDB = req.app.get('departmentsDB');
    const { name } = req.body;
    console.log(name);

    let jsonDepartments = departmentsDB.readFile();
    const nameExists = Object.values(jsonDepartments).some(department => department.name === name);
    if(nameExists){
        return res.status(httpStatus.CONFLICT).json({message: 'Department already in system.'})
    }

    const isObjectEmpty = !Object.keys(jsonDepartments).length;
    const highestKey = isObjectEmpty ? 0 : Math.max(...Object.keys(jsonDepartments).map(Number));
    const nextKey = highestKey + 1;

    jsonDepartments[nextKey] = {
        name: name,
        key: crypto.randomBytes(32).toString('hex')
    };
    departmentsDB.writeFile(jsonDepartments);

    return res.status(httpStatus.CREATED).json({message: 'Department successfully created'});
});

router.delete('/departments/:name', validateBody, (req, res) => {
    const departmentsDB = req.app.get('departmentsDB');
    let departmentsJson = departmentsDB.readFile();
    let foundName = false;
    const { name } = req.params;

    console.log(name);

    for (let key in departmentsJson) {
        if (departmentsJson.hasOwnProperty(key)) {
            const department = departmentsJson[key];
            if (department.name === name) {
                delete departmentsJson[key];
                foundName = true;
                break;
            }
        }
    }

    if(foundName !== true){
        return res.status(httpStatus.NOT_FOUND).json({ message: 'Department not found.' });
    }

    departmentsDB.writeFile(departmentsJson);
    return res.status(httpStatus.OK).json({ message: 'Department deleted successfully.' });
});

router.put('/', validateBody, (req, res) => {
    const ceoDB = req.app.get('ceoDB');
    const { name, email } = req.body;
    const {id, department} = ceoDB.readFile()

    const newCeo = {
        id: id,
        name: name,
        email: email,
        password: crypto.randomBytes(16).toString('hex'),
        department: department
    }

    ceoDB.writeFile(newCeo);
    return res.status(httpStatus.OK).json({message: 'Information modified.', data: newCeo});
});

router.get('/get_decrypt_keys', (req, res) => {
    return res.status(httpStatus.OK).json({
        message: 'Departments fetched.',
        data: departmentsDB.readFile()
    });
});

router.use((req, res) => {
    return res.status(httpStatus.NOT_FOUND).json({message: "Endpoint not found"});
})

module.exports = router;
