import bcrypt from 'bcrypt';
import { User } from '../models/index.js';
import { defaultPermissions } from '../models/usermanagement.model.js';

const buildUserResponse = (User) => {
    const plainUser = User.toJSON();
    delete plainUser.password;
    return plainUser;
};

const cloneDefaultPermissions = () => JSON.parse(JSON.stringify(defaultPermissions));

const parsePermissions = (permissions) => {
    if (typeof permissions !== 'string') {
        return permissions;
    }

    try {
        return JSON.parse(permissions);
    } catch (error) {
        return {};
    }
};

const parseBoolean = (value) => {
    if (value === true || value === 'true' || value === 1 || value === '1') return true;
    if (value === false || value === 'false' || value === 0 || value === '0') return false;
    return false;
};

const normalizePermissions = (permissions = {}, basePermissions = cloneDefaultPermissions()) => {
    const parsedBasePermissions = parsePermissions(basePermissions);
    const normalizedPermissions = {
        ...cloneDefaultPermissions(),
        ...parsedBasePermissions
    };
    let requestedPermissions = parsePermissions(permissions);

    if (!requestedPermissions || typeof requestedPermissions !== 'object' || Array.isArray(requestedPermissions)) {
        return normalizedPermissions;
    }

    Object.keys(normalizedPermissions).forEach((moduleName) => {
        const modulePermissions = requestedPermissions[moduleName];

        if (typeof modulePermissions === 'boolean' || typeof modulePermissions === 'string' || typeof modulePermissions === 'number') {
            normalizedPermissions[moduleName].view = parseBoolean(modulePermissions);
            return;
        }

        if (!modulePermissions || typeof modulePermissions !== 'object' || Array.isArray(modulePermissions)) {
            return;
        }

        if (modulePermissions.view !== undefined) {
            normalizedPermissions[moduleName].view = parseBoolean(modulePermissions.view);
        }
    });

    return normalizedPermissions;
};

const isNonEmptyString = (value) => typeof value === 'string' && value.trim() !== '';
const allowedRoles = ['admin', 'accountant', 'user', 'staff', 'manager'];
const allowedStatuses = ['active', 'inactive', 'blocked'];

const handleUserError = (res, error) => {
    console.log(error);

    if (error.name === "SequelizeValidationError") {
        return res.status(400).json({
            success: false,
            message: error.errors.map((item) => item.message).join(", ")
        });
    }

    if (error.name === "SequelizeDatabaseError") {
        return res.status(500).json({
            success: false,
            message: error.original?.sqlMessage || error.message
        });
    }

    return res.status(500).json({
        success: false,
        message: "Internal server error"
    });
};

// export const createUser = async (req, res) => {
//     try {
//         const { name, email, phone, role, password } = req.body;

//         if (!name || !email) {
//             return res.status(400).json({
//                 success: false,
//                 message: 'Name and email are required'
//             });
//         }

//         const existing = await User.findOne({
//             where: {
//                 [Op.or]: [{ email }, { name }]
//             }
//         });

//         if (existing) {
//             return res.status(400).json({ success: false, message: 'User with that email or name already exists' });
//         }

//         const hashedPassword = password ? await bcrypt.hash(password, 10) : null;

//         const user = await User.create({
//             name,
//             email,
//             phone,
//             role: role || 'user',
//             password: hashedPassword
//         });

//         res.status(201).json({ success: true, message: 'User created successfully', user });
//     } catch (error) {
//         console.log(error);
//         res.status(500).json({ success: false, message: 'Internal server error' });
//     }
// };

// export const getUsers = async (req, res) => {
//     try {
//         const users = await User.findAll({ order: [['created_at', 'DESC']] });
//         res.status(200).json({ success: true, users });
//     } catch (error) {
//         console.log(error);
//         res.status(500).json({ success: false, message: 'Internal server error' });
//     }
// };

// export const getUserById = async (req, res) => {
//     try {
//         const { id } = req.params;
//         const user = await User.findByPk(id);

//         if (!user) {
//             return res.status(404).json({ success: false, message: 'User not found' });
//         }

//         res.status(200).json({ success: true, user });
//     } catch (error) {
//         console.log(error);
//         res.status(500).json({ success: false, message: 'Internal server error' });
//     }
// };

// export const updateUser = async (req, res) => {
//     try {
//         const { id } = req.params;
//         const { password } = req.body;
//         const user = await User.findByPk(id);

//         if (!user) {
//             return res.status(404).json({ success: false, message: 'User not found' });
//         }

//         if (password) {
//             req.body.password = await bcrypt.hash(password, 10);
//         }

//         await user.update(req.body);
//         res.status(200).json({ success: true, message: 'User updated successfully', user });
//     } catch (error) {
//         console.log(error);
//         res.status(500).json({ success: false, message: 'Internal server error' });
//     }
// };

// export const deleteUser = async (req, res) => {
//     try {
//         const { id } = req.params;
//         const user = await User.findByPk(id);

//         if (!user) {
//             return res.status(404).json({ success: false, message: 'User not found' });
//         }

//         await user.destroy();
//         res.status(200).json({ success: true, message: 'User deleted successfully' });
//     } catch (error) {
//         console.log(error);
//         res.status(500).json({ success: false, message: 'Internal server error' });
//     }
// };




//
// CREATE USER
//


export const createUser = async (req, res) => {
    try {

        const {
            name,
            email,
            password,
            role,
            status,
            permissions
        } = req.body;

        // validation
        if (!isNonEmptyString(name) || !isNonEmptyString(email) || !isNonEmptyString(password)) {
            return res.status(400).json({
                success: false,
                message: "Name, email and password are required and must be strings"
            });
        }

        if (role !== undefined && !allowedRoles.includes(role)) {
            return res.status(400).json({
                success: false,
                message: `Role must be one of: ${allowedRoles.join(', ')}`
            });
        }

        if (status !== undefined && !allowedStatuses.includes(status)) {
            return res.status(400).json({
                success: false,
                message: `Status must be one of: ${allowedStatuses.join(', ')}`
            });
        }

        // duplicate check
        const existingUser = await User.findOne({
            where: { email }
        });

        if (existingUser) {
            return res.status(409).json({
                success: false,
                message: "Email already exists"
            });
        }

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

        const user = await User.create({
            name,
            email,
            password: hashedPassword,
            role: role || "user",
            status: status || "active",
            permissions: normalizePermissions(permissions)
        });

        res.status(201).json({
            success: true,
            message: "User created successfully",
            user: buildUserResponse(user)
        });

    } catch (error) {
        handleUserError(res, error);
    }
};


// GET ALL USERS
//
export const getUsers = async (req, res) => {
    try {

        const users = await User.findAll({
            attributes: { exclude: ["password"] },
            order: [["created_at", "DESC"]]
        });

        res.status(200).json({
            success: true,
            total: users.length,
            users
        });

    } catch (error) {
        handleUserError(res, error);
    }
};

//
// GET SINGLE USER
//
export const getUserById = async (req, res) => {
    try {

        const { id } = req.params;

        const user = await User.findByPk(id);

        if (!user) {
            return res.status(404).json({
                success: false,
                message: "User not found"
            });
        }

        res.status(200).json({
            success: true,
            user: buildUserResponse(user)
        });

    } catch (error) {
        handleUserError(res, error);
    }
};

//
// UPDATE USER
//
export const updateUser = async (req, res) => {
    try {

        const { id } = req.params;

        const user = await User.findByPk(id);

        if (!user) {
            return res.status(404).json({
                success: false,
                message: "User not found"
            });
        }

        const {
            name,
            email,
            password,
            role,
            status,
            permissions
        } = req.body;

        // duplicate email check
        if (email) {

            const existingEmail = await User.findOne({
                where: { email }
            });

            if (existingEmail && existingEmail.id != id) {
                return res.status(409).json({
                    success: false,
                    message: "Email already exists"
                });
            }
        }

        const updateData = {};

        if (name !== undefined) updateData.name = name;
        if (email !== undefined) updateData.email = email;
        if (role !== undefined) {
            if (!allowedRoles.includes(role)) {
                return res.status(400).json({
                    success: false,
                    message: `Role must be one of: ${allowedRoles.join(', ')}`
                });
            }

            updateData.role = role;
        }
        if (status !== undefined) {
            if (!allowedStatuses.includes(status)) {
                return res.status(400).json({
                    success: false,
                    message: `Status must be one of: ${allowedStatuses.join(', ')}`
                });
            }

            updateData.status = status;
        }
        if (permissions !== undefined) updateData.permissions = normalizePermissions(permissions, user.permissions);
        if (password !== undefined) {
            if (!isNonEmptyString(password)) {
                return res.status(400).json({
                    success: false,
                    message: "Password must be a non-empty string"
                });
            }

            updateData.password = await bcrypt.hash(password, 10);
        }

        await user.update(updateData);

        res.status(200).json({
            success: true,
            message: "User updated successfully",
            user: buildUserResponse(user)
        });

    } catch (error) {
        handleUserError(res, error);
    }
};

//
// DELETE USER
//
export const deleteUser = async (req, res) => {
    try {

        const { id } = req.params;

        const user = await User.findByPk(id);

        if (!user) {
            return res.status(404).json({
                success: false,
                message: "User not found"
            });
        }

        await user.destroy();

        res.status(200).json({
            success: true,
            message: "User deleted successfully"
        });

    } catch (error) {
        handleUserError(res, error);
    }
};

//
// PERMISSIONS TEMPLATE
//
export const getPermissionsTemplate = (req, res) => {
    res.status(200).json({
        success: true,
        permissions: cloneDefaultPermissions()
    });
};

//
// DASHBOARD STATS
//
export const getUserStats = async (req, res) => {
    try {

        const totalUsers = await User.count();

        const activeUsers = await User.count({
            where: { status: "active" }
        });

        const admins = await User.count({
            where: { role: "admin" }
        });

        const accountants = await User.count({
            where: { role: "accountant" }
        });

        res.status(200).json({
            success: true,
            stats: {
                totalUsers,
                activeUsers,
                admins,
                accountants
            }
        });

    } catch (error) {
        handleUserError(res, error);
    }
};
