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

module.exports = {
    filter,
    assignClientsToOutlet,
    getAllOutletClients,
    deleteOutletClients
};

async function getClientsIdsByName(names) {
    const clients = await dbSAPPS.Client.findAll({
        where: {
            display_name: names
        },
        attributes: ['id']
    });

    return clients.map(client => client.id);
}

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

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

    try {
        const outletClients = await dbSAPPS.OutletClient.findAll({
            include: [
                {
                    model: dbSAPPS.Outlet,
                    as: 'outlet',
                },
                {
                    model: dbSAPPS.Client,
                    as: 'client',
                }
            ],
            where: filterConditions,
            order: [['updatedAt', 'DESC']],
        });

        const result = outletClients.reduce((acc, outletClient) => {
            const id = outletClient.outlet.id;
            const outlet_id = outletClient.outlet.id;
            const outlet_name = outletClient.outlet.display_name;
            const outlet_code = outletClient.outlet.code;
            const client_name = outletClient.client.display_name;
            const client_code = outletClient.client.code;

            const createdAt = outletClient.createdAt;
            const updatedAt = outletClient.updatedAt;

            let existingOutlet = acc.find(item => item.outlet_id === outlet_id);
            if (!existingOutlet) {
                existingOutlet = {
                    id,
                    outlet_id,
                    outlet_name,
                    outlet_code,
                    // client_name,
                    // client_code,
                    clients: [],
                    clientsObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingOutlet);
            }

            existingOutlet.clients.push({ id: client_name, client_name, client_code });
            existingOutlet.clientsObject = existingOutlet.clients.reduce((acc, display_name) => {
                acc[display_name] = true;
                return acc;
            }, {});

            return acc;
        }, []);

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

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

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

        const outletClient = await dbSAPPS.OutletClient.findOne({ where: { outlet_id: outletId } });
        if (outletClient && update === false) {
            await transaction.rollback();
            return { success: false, message: 'Client is already assigned to a outlet, please update the assignment if necessary.' };
        }

        if (lastUsedOutletId && update === true) {
            const lastUse = await dbSAPPS.OutletClient.findOne({ where: { outlet_id: lastUsedOutletId } });
            if (lastUse) {
                await lastUse.destroy({ transaction });
            }
        }

        const outletIds = await getClientsIdsByName(clientNames);

        await outlet.setClients(outletIds, { transaction });
        await transaction.commit();
        return {
            success: true,
            message: 'Clients have been assigned to the outlet!'
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || 'Failed to assign clients to the outlet.';
        return { success: false, message: errorMessage };
    }
}
async function getAllOutletClients() {
    try {
        const outletClients = await dbSAPPS.OutletClient.findAll({
            include: [
                {
                    model: dbSAPPS.Outlet,
                    as: 'outlet',
                },
                {
                    model: dbSAPPS.Client,
                    as: 'client',
                }
            ],
            order: [['updatedAt', 'DESC']],
        });

        const result = outletClients.reduce((acc, outletClient) => {
            const id = outletClient.outlet.id;
            const outlet_id = outletClient.outlet.id;
            const outlet_name = outletClient.outlet.display_name;
            const outlet_code = outletClient.outlet.code;
            const client_name = outletClient.client.display_name;
            const client_code = outletClient.client.code;

            const createdAt = outletClient.createdAt;
            const updatedAt = outletClient.updatedAt;

            let existingOutlet = acc.find(item => item.outlet_id === outlet_id);
            if (!existingOutlet) {
                existingOutlet = {
                    id,
                    outlet_id,
                    outlet_name,
                    outlet_code,
                    // client_name,
                    // client_code,
                    clients: [],
                    clientsObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingOutlet);
            }

            existingOutlet.clients.push({ id: client_name, client_name, client_code });
            existingOutlet.clientsObject = existingOutlet.clients.reduce((acc, display_name) => {
                acc[display_name] = true;
                return acc;
            }, {});

            return acc;
        }, []);

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

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

        const outletClients = await dbSAPPS.OutletClient.findAll({
            where: { outlet_id: id },
            transaction
        });

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

        await dbSAPPS.OutletClient.destroy({
            where: { outlet_id: id },
            transaction
        });

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