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

module.exports = {
    filter,
    assignProjectsToEmailAccount,
    getAllEmailAccountProjects,
    deleteEmailAccountProjects
};

async function getProjectIdsByName(names) {
    const projects = await dbSAPPS.Project.findAll({
        where: {
            name: names
        },
        attributes: ['id']
    });

    return projects.map(project => project.id);
}

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

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

    try {
        const emailAccountProjects = await dbSAPPS.EmailAccountProject.findAll({
            include: [
                {
                    model: dbSAPPS.EmailAccount,
                    as: 'emailaccount',
                    attributes: ['id', 'email_account', 'password']
                },
                {
                    model: dbSAPPS.Project,
                    as: 'project',
                    attributes: ['id', 'name', 'display_name', 'slug_name']
                }
            ],
            where: filterConditions,
            order: [['updatedAt', 'DESC']],
        });

        const result = emailAccountProjects.reduce((acc, emailAccountProject) => {
            const id = emailAccountProject.emailaccount.id;
            const emailaccount_id = emailAccountProject.emailaccount.id;
            const email_account = emailAccountProject.emailaccount.email_account;
            const password = emailAccountProject.emailaccount.password;
            const projectName = emailAccountProject.project.name;
            const createdAt = emailAccountProject.createdAt;
            const updatedAt = emailAccountProject.updatedAt;

            let existingEmailAccount = acc.find(item => item.emailaccount_id === emailaccount_id);
            if (!existingEmailAccount) {
                existingEmailAccount = {
                    id,
                    emailaccount_id,
                    email_account,
                    password,
                    projects: [],
                    projectsObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingEmailAccount);
            }

            existingEmailAccount.projects.push(projectName);
            existingEmailAccount.projectsObject = existingEmailAccount.projects.reduce((acc, name) => {
                acc[name] = true;
                return acc;
            }, {});

            return acc;
        }, []);

        return {
            emailAccountProjects: result,
            success: true,
            message: 'Email account project has been loaded'
        };
    } catch (error) {
        console.error('Error retrieving email account project: ', error);
        const errorMessage = error.message || 'Failed to retrieve email account project. Please try again later.';
        return {
            success: false,
            message: errorMessage
        };
    }
}

async function assignProjectsToEmailAccount(params) {
    const transaction = await dbSAPPS.sequelize.transaction();
    try {
        const { emailAccountId, projectNames, update } = params;

        if (!emailAccountId || !Array.isArray(projectNames) || projectNames.length === 0) {
            return {
                success: false,
                message: 'Invalid input. Email account ID and Project IDs are required.'
            };
        }

        const emailAccount = await dbSAPPS.EmailAccount.findByPk(emailAccountId, { transaction });
        if (!emailAccount) {
            await transaction.rollback();
            return { success: false, message: 'Email account not found!' };
        }

        const emailAccountProjects = await dbSAPPS.EmailAccountProject.findOne({ where: { emailaccount_id: emailAccountId } });
        if (emailAccountProjects && update === false) {
            await transaction.rollback();
            return { success: false, message: 'Email account already exist, you must update!' };
        }

        const projectIds = await getProjectIdsByName(projectNames);

        await emailAccount.setProjects(projectIds, { transaction });
        await transaction.commit();
        return {
            success: true,
            message: 'Projects have been assigned to the email account!'
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || 'Failed to assign projects to the email account.';
        return { success: false, message: errorMessage };
    }
}

async function getAllEmailAccountProjects() {
    try {
        const emailAccountProjects = await dbSAPPS.EmailAccountProject.findAll({
            include: [
                {
                    model: dbSAPPS.EmailAccount,
                    as: 'emailaccount',
                    attributes: ['id', 'email_account', 'password']
                },
                {
                    model: dbSAPPS.Project,
                    as: 'project',
                    attributes: ['id', 'name', 'display_name', 'slug_name']
                }
            ],
            order: [['updatedAt', 'DESC']],
        });

        const result = emailAccountProjects.reduce((acc, emailAccountProject) => {
            const id = emailAccountProject.emailaccount.id;
            const emailaccount_id = emailAccountProject.emailaccount.id;
            const email_account = emailAccountProject.emailaccount.email_account;
            const password = emailAccountProject.emailaccount.password;
            const projectName = emailAccountProject.project.name;
            const createdAt = emailAccountProject.createdAt;
            const updatedAt = emailAccountProject.updatedAt;

            let existingEmailAccount = acc.find(item => item.emailaccount_id === emailaccount_id);
            if (!existingEmailAccount) {
                existingEmailAccount = {
                    id,
                    emailaccount_id,
                    email_account,
                    password,
                    projects: [],
                    projectsObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingEmailAccount);
            }

            existingEmailAccount.projects.push(projectName);
            existingEmailAccount.projectsObject = existingEmailAccount.projects.reduce((acc, name) => {
                acc[name] = true;
                return acc;
            }, {});

            return acc;
        }, []);

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

async function deleteEmailAccountProjects(id) {
    const transaction = await dbSAPPS.sequelize.transaction();
    try {
        const emailAccount = await dbSAPPS.EmailAccount.findByPk(id, { transaction });
        if (!emailAccount) {
            await transaction.rollback();
            return { success: false, message: 'Email account not found!' };
        }

        const emailAccountProjects = await dbSAPPS.EmailAccountProject.findAll({
            where: { emailaccount_id: id },
            transaction
        });

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

        await dbSAPPS.EmailAccountProject.destroy({
            where: { emailaccount_id: id },
            transaction
        });

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