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

module.exports = {
    filter,
    assignTerritoriesToEmployee,
    getAllEmployeeTerritories,
    deleteEmployeeTerritories
};

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

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

    try {
        const employeeTerritories = await dbSAPPS.EmployeeTerritory.findAll({
            include: [
                {
                    model: dbSAPPS.Employee,
                    as: 'employee',
                },
                {
                    model: dbSAPPS.Territory,
                    as: 'territory',
                    include: [{
                        model: dbSAPPS.Company,
                        as: 'company'
                    }]
                }
            ],
            where: filterConditions,
            order: [['updatedAt', 'DESC']],
        });

        const result = employeeTerritories.reduce((acc, employeeTerritory) => {
            const id = employeeTerritory.employee.id;
            const employee_id = employeeTerritory.employee.id;
            const employee_name = employeeTerritory.employee.employee_name;
            const employee_number = employeeTerritory.employee.employee_number;
            const territory_name = employeeTerritory.territory.name;
            const territory_id = employeeTerritory.territory.id;
            const company_name = employeeTerritory.territory.company.display_name;

            const createdAt = employeeTerritory.createdAt;
            const updatedAt = employeeTerritory.updatedAt;

            let existingEmployee = acc.find(item => item.employee_id === employee_id);
            if (!existingEmployee) {
                existingEmployee = {
                    id,
                    employee_id,
                    employee_name,
                    employee_number,
                    territory_name,
                    territory_id,
                    company_name,
                    territories: [],
                    territoriesObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingEmployee);
            }

            existingEmployee.territories.push(territory_id);
            existingEmployee.territoriesObject = existingEmployee.territories.reduce((acc, id) => {
                acc[id] = true;
                return acc;
            }, {});

            return acc;
        }, []);

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

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

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

        const employeeTerritories = await dbSAPPS.EmployeeTerritory.findOne({ where: { employee_id: employeeId } });
        if (employeeTerritories && update === false) {
            await transaction.rollback();
            return { success: false, message: 'Employee is already assigned to a territory, please update the assignment if necessary.' };
        }

        if (lastUsedEmployeeId && update === true) {
            const lastUse = await dbSAPPS.EmployeeTerritory.findOne({ where: { employee_id: lastUsedEmployeeId } });
            if (lastUse) {
                await lastUse.destroy({ transaction });
            }
        }

        if (update === false) {
            const territoriesUse = await dbSAPPS.EmployeeTerritory.findOne({ where: { territory_id: { [Op.in]: territoryIds } } });
            const territoryNames = await dbSAPPS.Territory.findAll({ where: { id: { [Op.in]: territoryIds } }, attributes: ['display_name'] });
            const territoryNamesList = territoryNames.map(territory => territory.display_name);
            const territoryNameWithIndonesia = territoryNamesList.some(name => name.toLowerCase().includes('indonesia'));
            if (territoriesUse && !territoryNameWithIndonesia) {
                await transaction.rollback();
                return { success: false, message: 'Territory is currently being utilized by another employee. Please select an alternative territory or update the existing assignment.' };
            }
        }

        await employee.setTerritories(territoryIds, { transaction });
        await transaction.commit();
        return {
            success: true,
            message: 'Territories have been assigned to the employee!'
        };
    } catch (error) {
        await transaction.rollback();
        const errorMessage = error.message || 'Failed to assign territories to the employee.';
        return { success: false, message: errorMessage };
    }
}

async function getAllEmployeeTerritories() {
    try {
        const employeeTerritories = await dbSAPPS.EmployeeTerritory.findAll({
            include: [
                {
                    model: dbSAPPS.Employee,
                    as: 'employee',
                },
                {
                    model: dbSAPPS.Territory,
                    as: 'territory',
                    include: [{
                        model: dbSAPPS.Company,
                        as: 'company'
                    }]
                }
            ],
            order: [['updatedAt', 'DESC']],
        });

        const result = employeeTerritories.reduce((acc, employeeTerritory) => {
            const id = employeeTerritory.employee.id;
            const employee_id = employeeTerritory.employee.id;
            const employee_name = employeeTerritory.employee.employee_name;
            const employee_number = employeeTerritory.employee.employee_number;
            const territory_name = employeeTerritory.territory.name;
            const territory_id = employeeTerritory.territory.id;
            const company_name = employeeTerritory.territory.company.display_name;

            const createdAt = employeeTerritory.createdAt;
            const updatedAt = employeeTerritory.updatedAt;

            let existingEmployee = acc.find(item => item.employee_id === employee_id);
            if (!existingEmployee) {
                existingEmployee = {
                    id,
                    employee_id,
                    employee_name,
                    employee_number,
                    territory_name,
                    territory_id,
                    company_name,
                    territories: [],
                    territoriesObject: {},
                    createdAt,
                    updatedAt
                };
                acc.push(existingEmployee);
            }

            existingEmployee.territories.push(territory_id);
            existingEmployee.territoriesObject = existingEmployee.territories.reduce((acc, id) => {
                acc[id] = true;
                return acc;
            }, {});

            return acc;
        }, []);

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

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

        const employeeTerritories = await dbSAPPS.EmployeeTerritory.findAll({
            where: { employee_id: id },
            transaction
        });

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

        await dbSAPPS.EmployeeTerritory.destroy({
            where: { employee_id: id },
            transaction
        });

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