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

class Entity extends Model {

    static associate(models) {

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

        Entity.belongsToMany(models.BankAccount, {
            through: "entity_accounts"
        });

        Entity.belongsToMany(models.Bank, {
            through: "entity_banks"
        });

        Entity.hasMany(models.Billable, { 
            as: "billable_entity", 
            foreignKey: "ent_id"
        });

        Entity.hasMany(models.InvoiceTemplate, { 
            as: "biller", 
            foreignKey: "biller_id"
        });

        Entity.hasMany(models.Tax, {
            as: "entity_tax",
            foreignKey: "ent_id"
        });

        Entity.hasMany(models.PEntity, {
            as: "entity_p_entity",
            foreignKey: "ent_id"
        });

        Entity.hasMany(models.Invoice, {
            as: "entity_invoice",
            foreignKey: "biller_id"
        });

        Entity.hasOne(models.EntityHeader, {
            as: "entity_header",
            foreignKey: "ent_id"
        });
    }

    async createEntity(data, creatorId) {
        try {
            const entity = await Entity.create({...data, creatorId});
            console.log(entity.toJSON());
            return entity.toJSON();
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }
    
    async readEntity(ordCol, ordDir, offsetVal, limitVal, id, searchTerm) {
        try {
            const [safeOrderCol, safeOrderDir] = sanitizeSort(ordCol, ordDir, [
                'id', 'name', 'nickname', 'type', 'description', 'pan', 'gst', 'tax_details', 'address', 'contact_no', 'email', 'status', 'creatorId', 'invoice_prefix', 'last_invoice_no', 'createdAt', 'updatedAt'
            ]);
            const { safeOffset, safeLimit } = sanitizePagination(offsetVal, limitVal);
            const entity = await Entity.findAll(
                {
                    where: {
                        creatorId: id,
                        ...(searchTerm
                            ? {
                                [Op.or]: [
                                    {name: {[Op.like]: `%${searchTerm}%`}},
                                    {nickname: {[Op.like]: `%${searchTerm}%`}},
                                ]
                            }
                            : {})
                    },
                    order: [[safeOrderCol, safeOrderDir]],
                    offset: safeOffset,
                    limit: safeLimit
                }
            );
            console.log(entity.map(e => e.toJSON()));
            return entity.map(e => e.toJSON());
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }

    async readEntityRow(data) {
        try {
            const entity = await Entity.findOne(
                {
                    where: {
                        id: data.id
                    }
                }
            )
            console.log(entity.toJSON());
            return entity.toJSON();
        }
        catch (err) {
            console.log(err);
            return err;
        }
    } 

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

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

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

    async countEntity(id) {
        try {
            const count = await Entity.count({
                where: {
                    creatorId: id
                }
            });
            console.log(count);
            return count;
        }
        catch (err) {
            console.log(err);
            return err;
        }
    }
}

Entity.init(
    {
        name: {
            type: DataTypes.STRING(100),
            allowNull: false
        },
        nickname: {
            type: DataTypes.STRING(25),
            allowNull: false
        },
        type: {
            type: DataTypes.STRING(25),
            allowNull: false
        },
        description: {
            type: DataTypes.TEXT,
            allowNull: true
        },
        pan: {
            type: DataTypes.STRING(25),
            allowNull: false
        },
        gst: {
            type: DataTypes.STRING(25),
            allowNull: false
        },
        tax_details: {
            type: DataTypes.JSON,
            allowNull: false
        },
        address: {
            type: DataTypes.STRING(250),
            allowNull: false
        },
        contact_no: {
            type: DataTypes.STRING(25),
            allowNull: false
        },
        email: {
            type: DataTypes.STRING(50),
            allowNull: false
        },
        status: {
            type: DataTypes.STRING(25),
            allowNull: false
        },
        creatorId: {
            type: DataTypes.INTEGER,
            allowNull: false
        },
        invoice_prefix: {
            type: DataTypes.STRING(25),
            allowNull: true
        },
        last_invoice_no: {
            type: DataTypes.INTEGER,
            allowNull: true
        },
    },
    {
        sequelize,
        modelName: "Entity",
        tableName: "entity"
    }
)

module.exports = Entity;