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

module.exports = {
    filter,
    assignCoursesToProject,
    getAllProjectCourse,
    deleteProjectCourse
};

async function getCoursesIdsByName(names) {
    const courses = await dbSAPPS.Course.findAll({
        where: {
            title: names
        },
        attributes: ['id']
    });

    return courses.map(course => course.id);
}

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

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

    try {
        const projectCourses = await dbSAPPS.ProjectCourse.findAll({
            include: [
                {
                    model: dbSAPPS.Project,
                    as: 'project',
                },
                {
                    model: dbSAPPS.Course,
                    as: 'course',
                }
            ],
            where: filterConditions,
            order: [['updatedAt', 'DESC']],
        });

        const result = projectCourses.reduce((acc, projectCourse) => {
            const id = projectCourse.id;
            const project_id = projectCourse.project.id;
            const project_name = projectCourse.project.name;
            const course_id = projectCourse.course.id;
            const course_title = projectCourse.course.title;

            const createdAt = projectCourse.createdAt;
            const updatedAt = projectCourse.updatedAt;

            let existingProject = acc.find(item => item.project_id === project_id);
            if (!existingProject) {
                existingProject = {
                    id,
                    project_id,
                    project_name,
                    course_id,
                    course_title,
                    courses: [],
                    coursesObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingProject);
            }

            existingProject.courses.push(course_title);
            existingProject.coursesObject = existingProject.courses.reduce((acc, title) => {
                acc[title] = true;
                return acc;
            }, {});

            return acc;
        }, []);

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

async function assignCoursesToProject(params) {
    const transaction = await dbSAPPS.sequelize.transaction();
    try {
        const { projectId, lastUsedProjectId, courseNames, update } = params;
        if (!projectId || !Array.isArray(courseNames) || courseNames.length === 0) {
            return {
                success: false,
                message: 'Invalid input. Please ensure that all required fields are provided in the correct format.'
            };
        }

        const project = await dbSAPPS.Project.findByPk(projectId, { transaction });
        if (!project) {
            await transaction.rollback();
            return { success: false, message: 'Project not found!' };
        }

        const projectCourse = await dbSAPPS.ProjectCourse.findOne({ where: { project_id: projectId } });
        if (projectCourse && update === false) {
            await transaction.rollback();
            return { success: false, message: 'Project is already assigned to a course, please update the assignment if necessary.' };
        }

        if (lastUsedProjectId && update === true) {
            const lastUse = await dbSAPPS.ProjectCourse.findOne({ where: { project_id: lastUsedProjectId } });
            if (lastUse) {
                await lastUse.destroy({ transaction });
            }
        }

        const courseIds = await getCoursesIdsByName(courseNames);

        await project.setCourses(courseIds, { transaction });
        await transaction.commit();
        return {
            success: true,
            message: 'Courses have been assigned to the project!'
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || 'Failed to assign courses to the project.';
        return { success: false, message: errorMessage };
    }
}


async function getAllProjectCourse() {
    try {
        const projectCourses = await dbSAPPS.ProjectCourse.findAll({
            include: [
                {
                    model: dbSAPPS.Project,
                    as: 'project',
                },
                {
                    model: dbSAPPS.Course,
                    as: 'course',
                },
            ],
            order: [['updatedAt', 'DESC']],
        });

        const result = projectCourses.reduce((acc, projectCourse) => {
            const id = projectCourse.project.id;
            const project_id = projectCourse.project.id;
            const project_name = projectCourse.project.name;
            const course_id = projectCourse.course.id;
            const course_title = projectCourse.course.title;

            const createdAt = projectCourse.createdAt;
            const updatedAt = projectCourse.updatedAt;

            let existingProject = acc.find(item => item.project_id === project_id);
            if (!existingProject) {
                existingProject = {
                    id,
                    project_id,
                    project_name,
                    course_id,
                    course_title,
                    courses: [],
                    coursesObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingProject);
            }

            existingProject.courses.push(course_title);
            existingProject.coursesObject = existingProject.courses.reduce((acc, title) => {
                acc[title] = true;
                return acc;
            }, {});

            return acc;
        }, []);

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

async function deleteProjectCourse(id) {
    const transaction = await dbSAPPS.sequelize.transaction();
    try {
        const project = await dbSAPPS.Project.findByPk(id, { transaction });
        if (!project) {
            await transaction.rollback();
            return { success: false, message: 'Project not found!' };
        }

        const projectCourse = await dbSAPPS.ProjectCourse.findAll({
            where: { project_id: id },
            transaction
        });

        if (projectCourse.length === 0) {
            await transaction.rollback();
            return {
                success: false,
                message: 'Project has no associated course, so it was not deleted.'
            };
        }

        await dbSAPPS.ProjectCourse.destroy({
            where: { project_id: id },
            transaction
        });

        await transaction.commit();
        return {
            success: true,
            message: 'Project and courses has been deleted!'
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || 'Failed to delete Project and courses.';
        return { success: false, message: errorMessage };
    }
}



