const { Model, DataTypes, Op } = require('sequelize');
const sequelize = require('../config/db.js');
const { sanitizeSort, sanitizePagination } = require('./querySafety.js');

class User extends Model {

    static associate(models) {

        User.belongsToMany(models.Entity, { 
            through: "user_entity"
        });

        User.belongsToMany(models.PEntity, { 
            through: "user_p_entity"
        });

        User.belongsToMany(models.Group, {
            through: "user_groups"
        });

        User.hasMany(models.ChangeLog, {
            as: "change_logs",
            foreignKey: "user_id",
        });
    }

    async createUser(data) {
        try {
            const user = await User.create(data);
            console.log(user.toJSON());
            return user.toJSON();
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }
    
    async getUsers() {
        try {
            const users = await User.findAll();
            // console.log(users.map(u => u.toJSON()));
            return users.map(u => u.toJSON());
        }
        catch (err) {
            // console.log(err);
            return err;
        }
    }

    async readUser(ordCol, ordDir, offsetVal, limitVal, searchTerm) {
        try {
            const [safeOrderCol, safeOrderDir] = sanitizeSort(ordCol, ordDir, [
                'id', 'fname', 'mname', 'lname', 'gender', 'username', 'email', 'phone', 'status', 'createdAt', 'updatedAt'
            ]);
            const { safeOffset, safeLimit } = sanitizePagination(offsetVal, limitVal);
            const where = searchTerm ? {
                [Op.or]: [
                    { username: { [Op.like]: `%${searchTerm}%` } },
                    { fname:    { [Op.like]: `%${searchTerm}%` } },
                    { lname:    { [Op.like]: `%${searchTerm}%` } },
                    { email:    { [Op.like]: `%${searchTerm}%` } }
                ]
            } : {};
            const user = await User.findAll({
                where,
                attributes: { exclude: ['password'] },
                order: [[safeOrderCol, safeOrderDir]],
                offset: safeOffset,
                limit: safeLimit
            });
            return user.map(u => u.toJSON());
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }

    async countUsers(searchTerm) {
        try {
            const where = searchTerm ? {
                [Op.or]: [
                    { username: { [Op.like]: `%${searchTerm}%` } },
                    { fname:    { [Op.like]: `%${searchTerm}%` } },
                    { lname:    { [Op.like]: `%${searchTerm}%` } },
                    { email:    { [Op.like]: `%${searchTerm}%` } }
                ]
            } : {};
            return await User.count({ where });
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }

    async readUserRow(data) {
        try {
            const user = await User.findOne(
                {
                    where: {
                        id: data.id
                    },
                    attributes: { exclude: ['password'] }
                }
            )
            return user ? user.toJSON() : null;
        }
        catch (err) {
            console.log(err);
            return err;
        }
    } 

    async updateUser(data) {
        try {
            const result = await User.update(data.data, {where: {id: data.id}});
            console.log(`User with ${data.id} updated`, result[0]);
            return result[0];
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }

    async deleteUser(data) {
        try {
            const result = await User.destroy(
                {
                    where: {id: data.id}
                }
            );

            if (result) {
                console.log(`User ${data.id} deleted`);
                return `User ${data.id} deleted`;
            }
            else {
                console.log(`User ${data.id} not found`);
                return `User ${data.id} not found`;
            }
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }

    async countUser() {
        try {
            const count = await User.count();
            console.log(count);
            return count;
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }
}

User.init(
    {
        fname: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
        mname: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
        lname: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
        gender: {
            type: DataTypes.STRING(25),
            allowNull: false
        },
        username: {
            type: DataTypes.STRING(50),
            allowNull: false,
            unique: true
        },
        password: {
            type: DataTypes.STRING(250),
            allowNull: false
        },
        email: {
            type: DataTypes.STRING(75),
            allowNull: false
        },
        phone: {
            type: DataTypes.STRING(15),
            allowNull: false
        },
        status: {
            type: DataTypes.STRING(25),
            allowNull: false
        }
    },
    {
        sequelize,
        modelName: "User",
        tableName: "users"
    }
)

module.exports = User;