const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
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?.coursesId) {
            filterConditions.id = {
                [Op.in]: params?.coursesId
            };
        }

        const courses = await dbSAPPS.Course.findAll({
            where: filterConditions,
            order: [['modified', 'DESC']],
            include: [
                {
                    model: dbSAPPS.CourseChild,
                    as: 'coursechilds'
                }
            ]
        });

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

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

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

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

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

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

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

    try {
        const courses = await dbSAPPS.Course.findAll({
            where: filterConditions,
            order: [['modified', 'DESC']],
            include: [
                {
                    model: dbSAPPS.CourseChild,
                    as: 'coursechilds'
                }
            ]
        });

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

        return {
            success: false,
            message: errorMessage
        };
    }
}

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

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

        filterConditions.enabled = {
            [Op.eq]: true
        };

        const courses = await dbSAPPS.Course.findAll({
            attributes: ['id', 'title', 'description', 'url', 'icon'],
            where: filterConditions,
            order: [['modified', 'DESC']],
            include: [
                {
                    model: dbSAPPS.CourseChild,
                    as: 'coursechilds'
                }
            ]
        });

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

        return {
            success: false,
            message: errorMessage
        };
    }
}

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

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


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

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

        if (!params.creation) params.creation = Date.now();
        if (!params.modified) params.modified = Date.now();
        if (!params.modified_by) params.modified_by = 1;
        if (!params.owner) params.owner = 1;

        const course = await dbSAPPS.Course.create(params, { transaction });

        if (params.course_child) {
            params.course_child = JSON.parse(params.course_child);
        }

        if (Array.isArray(params.course_child) && params.course_child.length > 0) {
            const courseChildData = params.course_child.map(courseChild => ({
                ...courseChild,
                course_id: course.id
            }));
            await dbSAPPS.CourseChild.bulkCreate(courseChildData, { transaction });
        }

        if (params.progressions) {
            params.progressions = JSON.parse(params.progressions);
        }

        if (Array.isArray(params.progressions) && params.progressions.length > 0) {
            const progressionsData = params.progressions.map(progression => ({
                development_id: development.id,
                scope_development: progression.factor_name,
                achievement_detail: progression.achievement_detail,
                achievement_level: progression.achievement_level
            }));
            await dbSAPPS.Progression.bulkCreate(progressionsData, { transaction });
        }

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

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

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

        await course.update(params, { transaction });

        if (params.course_child) {
            params.course_child = JSON.parse(params.course_child);
        }

        if (Array.isArray(params.course_child) && params.course_child.length > 0) {
            await dbSAPPS.CourseChild.destroy({ where: { course_id: id }, transaction });
            const courseChildData = params.course_child.map(courseChild => ({
                ...courseChild,
                course_id: id
            }));
            await dbSAPPS.CourseChild.bulkCreate(courseChildData, { transaction });
        } else {
            await dbSAPPS.CourseChild.destroy({ where: { course_id: id }, transaction });
        }

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

async function enabled(id, params) {
    try {
        const course = await dbSAPPS.Course.findByPk(id);
        if (!course) return {
            success: false,
            message: 'Course 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;

        await course.update(updateData);

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

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

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