const dbSAPPS = require('../../helpers/db');
require('dotenv').config();
const { Op } = require('sequelize');

module.exports = {
    create,
    getAll,
    filter,
    option,
    count,
    update,
    enabled,
    delete: _delete
};

async function getAll(params) {
    try {
        const filterConditions = {};

        if (params?.projectsId) {
            filterConditions.project_id = {
                [Op.in]: params?.projectsId
            };
        }

        const developments = await dbSAPPS.Development.findAll({
            where: filterConditions,
            order: [['modified', 'DESC']],
            include: [
                { model: dbSAPPS.Aspect, as: 'aspects' },
                { model: dbSAPPS.Factor, as: 'factors' },
                { model: dbSAPPS.ProgressionTable, as: 'progressiontables' },
                { model: dbSAPPS.Level, as: 'levels' },
            ]
        });

        return {
            developments,
            success: true,
            message: 'Developments has been loaded!'
        };
    } catch (error) {
        const errorMessage = error.message || 'Failed to load developments!';
        return {
            success: false,
            message: errorMessage
        };
    }
}

async function filter(params) {
    const filterConditions = {};

    if (params?.projectsId) {
        filterConditions.project_id = {
            [Op.in]: params?.projectsId
        };
    }

    if (params.title) {
        filterConditions.title = {
            [Op.like]: `%${params.title}%`,
        };
    }

    if (params.description) {
        filterConditions.description = {
            [Op.like]: `%${params.description}%`,
        };
    }

    if (params.project_id) {
        filterConditions.project_id = {
            [Op.eq]: params.project_id,
        };
    }

    if (params.enabled) {
        filterConditions.enabled = {
            [Op.eq]: params.enabled === "1" ? true : false,
        };
    }

    try {
        const developments = await dbSAPPS.Development.findAll({
            where: filterConditions,
            order: [['modified', 'DESC']],
            include: [
                { model: dbSAPPS.Aspect, as: 'aspects' },
                { model: dbSAPPS.Factor, as: 'factors' },
                { model: dbSAPPS.ProgressionTable, as: 'progressiontables' },
                { model: dbSAPPS.Level, as: 'levels' },
            ]
        });

        return {
            developments,
            success: true,
            message: 'Developments has been loaded!'
        };
    } catch (error) {
        console.error('Error retrieving developments: ', error);
        const errorMessage = error.message || 'Failed to retrieve developments. Please try again later.';
        return {
            success: false,
            message: errorMessage
        };
    }
}

async function option() {
    try {
        const developments = await dbSAPPS.Development.findAll({
            attributes: ['id', 'title', 'description'],
            where: { enabled: true },
            order: [['title', 'ASC']]
        });

        return {
            developments,
            success: true,
            message: "Developments has been loaded!"
        };
    } catch (error) {
        console.error('Error retrieving developments: ', error);
        const errorMessage = error.message || 'Failed to retrieve developments. Please try again later.';
        return {
            success: false,
            message: errorMessage
        };
    }
}

async function count() {
    try {
        const count = await dbSAPPS.Development.count({
            where: { enabled: true }
        });

        return {
            count,
            success: true,
            message: 'Developments has been loaded!'
        };
    } catch (error) {
        console.error('Error counting developments: ', error);
        return {
            success: false,
            message: 'Failed to retrieve developments count. Please try again later.'
        };
    }
}

async function create(params) {
    const transaction = await dbSAPPS.sequelize.transaction();
    try {
        if (!params.title || !params.description) { return { success: false, message: 'Title and description are required!' } }

        const existingTitle = await dbSAPPS.Development.findOne({ where: { title: params.title } });
        if (existingTitle) return { success: false, message: `Title "${params.title}" is already taken.` };

        const development = await dbSAPPS.Development.create({
            creation: params.creation,
            modified: params.modified,
            modified_by: params.modified_by,
            owner: params.owner,
            enabled: params.enabled,
            title: params.title,
            description: params.description,
            aspect_description: params.aspect_description,
            factor_description: params.factor_description,
            progression_table_description: params.progression_table_description,
            impact_description: params.impact_description,
            project_id: params.project_id,
            icon: params.icon,
            url: params.url
        }, { transaction });

        if (params.aspects) {
            try {
                params.aspects = JSON.parse(params.aspects);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for aspects.'
                };
            }
        }

        if (Array.isArray(params.aspects) && params.aspects.length > 0) {
            const aspectData = params.aspects.map(aspect => ({
                development_id: development.id,
                aspect_name: aspect.aspect_name,
                description: aspect.description
            }));
            await dbSAPPS.Aspect.bulkCreate(aspectData, { transaction });
        }

        if (params.factors) {
            try {
                params.factors = JSON.parse(params.factors);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for factors.'
                };
            }
        }

        if (Array.isArray(params.factors) && params.factors.length > 0) {
            const factorData = params.factors.map(factor => ({
                development_id: development.id,
                factor_name: factor.factor_name,
                description: factor.description
            }));
            await dbSAPPS.Factor.bulkCreate(factorData, { transaction });
        }

        if (params.progressiontables) {
            try {
                params.progressiontables = JSON.parse(params.progressiontables);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for progression tables.'
                };
            }
        }

        if (Array.isArray(params.progressiontables) && params.progressiontables.length > 0) {
            const progressionTableData = params.progressiontables.map(progressionTable => ({
                development_id: development.id,
                scope_development: progressionTable.factor_name,
                achievement_detail: progressionTable.achievement_detail,
                achievement_level: progressionTable.achievement_level
            }));
            await dbSAPPS.ProgressionTable.bulkCreate(progressionTableData, { transaction });
        }

        if (params.levels) {
            try {
                params.levels = JSON.parse(params.levels);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for levels.'
                };
            }
        }

        if (Array.isArray(params.levels) && params.levels.length > 0) {
            const levelData = params.levels.map(level => ({
                development_id: development.id,
                level_group: level.level_group,
                level_name: level.level_name,
                description: level.description
            }));
            await dbSAPPS.Level.bulkCreate(levelData, { transaction });
        }

        await transaction.commit();
        return {
            success: true,
            message: 'Development has been created!',
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || 'An error occurred during creating development.';
        return {
            success: false,
            message: errorMessage
        };
    }
}

async function update(id, params) {
    const transaction = await dbSAPPS.sequelize.transaction();
    try {
        const development = await dbSAPPS.Development.findByPk(id);
        if (!development) {
            return {
                success: false,
                message: 'Development not found!'
            };
        }

        if (params.title && params.title !== development.title) {
            const existingTitle = await dbSAPPS.Development.findOne({ where: { title: params.title } });
            if (existingTitle && existingTitle.id != id) {
                return {
                    success: false,
                    message: `Title "${params.title}" is already taken. Try again!`
                };
            }
        }

        await development.update({
            creation: params.creation || development.creation,
            modified: params.modified || development.modified,
            modified_by: params.modified_by || development.modified_by,
            owner: params.owner || development.owner,
            enabled: params.enabled !== undefined ? params.enabled : development.enabled,
            title: params.title || development.title,
            description: params.description || development.description,
            aspect_description: params.aspect_description || development.aspect_description,
            factor_description: params.factor_description || development.factor_description,
            progression_table_description: params.progression_table_description || development.progression_table_description,
            impact_description: params.impact_description || development.impact_description,
            project_id: params.project_id || development.project_id,
            icon: params.icon || development.icon,
            url: params.url || development.url
        }, { transaction });

        if (params.aspects) {
            try {
                params.aspects = JSON.parse(params.aspects);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for aspects.'
                };
            }
        }

        if (Array.isArray(params.aspects)) {
            await dbSAPPS.Aspect.destroy({ where: { development_id: id }, transaction });
            if (params.aspects.length > 0) {
                const aspectData = params.aspects.map(aspect => ({
                    development_id: id,
                    aspect_name: aspect.aspect_name,
                    description: aspect.description
                }));
                await dbSAPPS.Aspect.bulkCreate(aspectData, { transaction });
            }
        } else {
            await dbSAPPS.Aspect.destroy({ where: { development_id: id }, transaction });
        }

        if (params.factors) {
            try {
                params.factors = JSON.parse(params.factors);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for factors.'
                };
            }
        }

        if (Array.isArray(params.factors)) {
            await dbSAPPS.Factor.destroy({ where: { development_id: id }, transaction });
            if (params.factors.length > 0) {
                const factorData = params.factors.map(factor => ({
                    development_id: id,
                    factor_name: factor.factor_name,
                    description: factor.description
                }));
                await dbSAPPS.Factor.bulkCreate(factorData, { transaction });
            }
        } else {
            await dbSAPPS.Factor.destroy({ where: { development_id: id }, transaction });
        }

        if (params.progressiontables) {
            try {
                params.progressiontables = JSON.parse(params.progressiontables);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for progression tables.'
                };
            }
        }

        if (Array.isArray(params.progressiontables)) {
            await dbSAPPS.ProgressionTable.destroy({ where: { development_id: id }, transaction });
            if (params.progressiontables.length > 0) {
                const progressionTableData = params.progressiontables.map(progressionTable => ({
                    development_id: development.id,
                    scope_development: progressionTable.scope_development,
                    achievement_detail: progressionTable.achievement_detail,
                    achievement_level: progressionTable.achievement_level
                }));
                await dbSAPPS.ProgressionTable.bulkCreate(progressionTableData, { transaction });
            }
        } else {
            await dbSAPPS.ProgressionTable.destroy({ where: { development_id: id }, transaction });
        }

        if (params.levels) {
            try {
                params.levels = JSON.parse(params.levels);
            } catch (error) {
                return {
                    success: false,
                    message: 'Invalid JSON format for levels.'
                };
            }
        }

        if (Array.isArray(params.levels)) {
            await dbSAPPS.Level.destroy({ where: { development_id: id }, transaction });
            if (params.levels.length > 0) {
                const levelData = params.levels.map(level => ({
                    development_id: development.id,
                    level_group: level.level_group,
                    level_name: level.level_name,
                    description: level.description
                }));
                await dbSAPPS.Level.bulkCreate(levelData, { transaction });
            }
        } else {
            await dbSAPPS.Level.destroy({ where: { development_id: id }, transaction });
        }

        await transaction.commit();
        return {
            success: true,
            message: 'Development has been updated!'
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || 'Failed to update development.';
        return {
            success: false,
            message: errorMessage
        };
    }
}

async function enabled(id, params) {
    try {
        const development = await dbSAPPS.Development.findByPk(id);
        if (!development) return {
            success: false,
            message: 'Development not found!'
        };

        const updateData = {};
        updateData.enabled = params.enabled;
        if (params.modified_by) updateData.modified_by = params.modified_by;
        if (params.modified) updateData.modified = params.modified;

        // debug
        // console.log('id', id);
        // console.log('params', params);
        // console.log('updateData', updateData)

        await development.update(updateData);
        return {
            success: true,
            message: 'Development has been updated!'
        };
    } catch (error) {
        const errorMessage = error.message || 'Failed to update development.';
        return {
            success: false,
            message: errorMessage
        };
    }
}

async function _delete(id) {
    try {
        const development = await dbSAPPS.Development.findByPk(id);
        if (!development) return { success: false, message: 'Development not found!' };

        await development.destroy();
        return {
            success: true,
            message: 'Development has been deleted!'
        };
    } catch (error) {
        const errorMessage = error.message || 'Failed to delete development.';
        return {
            success: false,
            message: errorMessage
        };
    }
}
