const SplitEstimateModel = require('../models/SplitEstimate');
const SplitManagementModel = require('../models/SplitManagementModel');
const RequestModel = require('../models/request');
const CustomerOrderModel = require('../models/customerOrder');
const CustomerOrderProduct = require('../models/customerOrderProduct')
const ProductModel = require('../models/product');
const moment = require('moment');
const { FACILITY_ID } = require('../config/SplitManagementDb');
const Settings = require("../models/settings");
const RequestActivity = require('../models/RequestActivity');
const { getRequestAttachmentImagesByDocumentId, deleteRequestAttachmentImagesByDocumentId, addRequestAttachmentImage } = require('../models/documentRepository');
const { convertPdfToPngHelper } = require('./request');
const RequestUpdates = require('../models/requestUpdates');

const addSplitEstimate = async (req,res) => {
    try {
        const { values ,currentFacilityId,userId,selectedRecipes,splitPercentage} = req.body;
        const attachments = values?.avatarUrl;
        console.log("requestData",req.body)
        const uniqueId = Number(`${Date.now()}${Math.floor(100 + Math.random() * 900)}`);
        const valuesForDb = {
            id: uniqueId,
            name: values?.name,
            description: (values?.description || '').replace(/\r?\n/g, '\n'),
            description_lines: (values?.description || '') ? (values?.description || '').replace(/\r?\n/g, '\n').split('\n') : [],
            notes: (values?.notes || '').replace(/\r?\n/g, '\n'),
            notes_lines: (values?.notes || '') ? (values?.notes || '').replace(/\r?\n/g, '\n').split('\n') : [],
            origin_facility_id: currentFacilityId,
            to_facility_id: values?.facility_type?.id,
            created_at: moment().unix(),
            timestamp: moment().unix(),
            added_by: userId,
        }
        const splitEstimate = await SplitEstimateModel.addSplitEstimate(valuesForDb);

        if(splitEstimate){
            let attachmentsData = [];
            
            // Get client/partner details for update
            const Client = require('../models/client');
            let clientDetails = await Client.getPartnerByUserId(userId);
            let splitEstimateUpdatesData = {
                split_estimate_id: splitEstimate,
                partner_id: clientDetails?.id || 0,
                partner_name: clientDetails?.name || '',
                activity: `Split Estimate "${values?.name}" has been created`,
                added_by: userId,
                timestamp: moment().unix(),
            }
            const splitEstimateUpdates = await RequestUpdates.addSplitEstimateUpdates(splitEstimateUpdatesData);
            // Check if attachments exist and is an array before processing
            if(attachments && Array.isArray(attachments) && attachments.length > 0){
                for(let i=0;i<attachments.length;i++){
                    const attachment = attachments[i];
                    const attachmentData = {
                        url: attachment.url,
                        file_type: attachment.file_type,
                        split_estimate_id: splitEstimate,
                        timestamp: moment().unix(),
                    }
                    const attachmentResult = await SplitEstimateModel.addSplitEstimateAttachments(attachmentData);
                    attachmentsData.push(attachmentData);
                    // Convert PDF to PNG (same as addRequest)
                    const newAttachmentId = attachmentResult?.id ?? attachmentResult?.dataValues?.id;
                    if (newAttachmentId) {
                        // const isPdfFile =
                        //     (attachment.file_type === 'application/pdf' || attachment.file_type === 'pdf') ||
                        //     (attachment.extension && String(attachment.extension).toLowerCase() === 'pdf');
                        // if (isPdfFile) {
                        //     try {
                        //         await convertPdfToPngHelper(newAttachmentId, SplitEstimateModel.getSplitEstimateAttachmentByIdForConversion, 'split_estimate');
                        //         console.log(`PDF conversion completed for split estimate document ID: ${newAttachmentId}`);
                        //     } catch (conversionError) {
                        //         console.error(`Error converting PDF for split estimate document ${newAttachmentId}:`, conversionError);
                        //     }
                        // }
                    }
                }
            }
            let recipesData = [];
            if(selectedRecipes && Array.isArray(selectedRecipes) && selectedRecipes.length > 0){
                for(let i=0;i<selectedRecipes.length;i++){
                    const recipe = selectedRecipes[i];
                    const recipeData = {
                        product_name: recipe?.product_name,
                        expected_cost: 0,
                        split_estimate_id: splitEstimate,
                        split_percentage: recipe?.split_percentage || splitPercentage,
                    }
                    const recipeResult = await SplitEstimateModel.addSplitEstimateRecipes(recipeData);
                    console.log('recipeResult---', recipeResult)
                    recipesData.push(recipeData);
                }
            }

            // Sync to other installation if target facility is different from current
            const targetFacilityId = values?.facility_type?.id;
            if(targetFacilityId && targetFacilityId !== currentFacilityId){
                console.log(`Syncing split estimate to facility_id: ${targetFacilityId}`);
                
                // Prepare data for other installation (swap origin and target facility IDs)
                const otherInstallationData = {
                    ...valuesForDb,
                   };

                // Sync to other installation
                const syncResult = await SplitManagementModel.syncSplitEstimateAcrossInstallations(
                    otherInstallationData, 
                    attachmentsData, 
                    targetFacilityId,
                    recipesData
                );

                if(syncResult.success){
                    console.log(`Successfully synced to other installation: ${syncResult.message}`);
                } else {
                    console.log(`Failed to sync to other installation: ${syncResult.message}`);
                }
            }

            res.send({status:1,message:"Split Estimate Added Successfully"});
        }else{
            res.send({status:0,message:"Failed to Add Split Estimate"});
        }
    }catch(error){
        console.log("error",error)
        res.send({status:0,message:"Server Error",error:error});
    }
}

const fetchAllSplitEstimates = async (req,res) => {
    try {
        const {userId, userType, search, page, rowsPerPage, sort, where} = req.body;
        const result = await SplitEstimateModel.getAllSplitEstimates(search, page, rowsPerPage, sort, where);
        const otherInstallationSplitManagementSettings = await SplitManagementModel.getAllSplitManagementSettingsFromOtherInstallations();
        const currentFacilitySplitManagementSettings = await SplitManagementModel.getAllSplitManagementSettings();
        if(result){
            res.send({
                status:1, 
                message:"Split Estimates Fetched Successfully", 
                result: result.data,
                totalCount: result.totalCount,
                currentFacilitySplitManagementSettings,
                otherInstallationSplitManagementSettings
            });
        } else {
            res.send({status:0, message:"Failed to fetch Split Estimates"});
        }
    }catch(error){
        console.log("error", error);
        res.send({status:0, message:"Server Error", error:error});
    }
}

const fetchAllSplitEstimateDetails = async (req,res) => {
    try {
        const {id, userId, userType} = req.body;
        const splitEstimate = await SplitEstimateModel.getSplitEstimateById(id);
        if (splitEstimate) {
            splitEstimate.description = (splitEstimate.description || '').replace(/\r?\n/g, '\n');
            splitEstimate.description_lines = splitEstimate.description ? splitEstimate.description.split('\n') : [];
            splitEstimate.notes = (splitEstimate.notes || '').replace(/\r?\n/g, '\n');
            splitEstimate.notes_lines = splitEstimate.notes ? splitEstimate.notes.split('\n') : [];
        }
        const splitEstimateAttachments = await SplitEstimateModel.getSplitEstimateAttachmentsBySplitEstimateId(id);
        const splitEstimateRecipes = await SplitEstimateModel.fetchAllSplitEstimateRecipes(id);
        const splitEstimateServices = await SplitEstimateModel.getSplitEstimateServicesBySplitEstimateId(id);
        const otherInstallationSplitManagementSettings = await SplitManagementModel.getAllSplitManagementSettingsFromOtherInstallations();
        const currentFacilitySplitManagementSettings = await SplitManagementModel.getAllSplitManagementSettings();
        
        // Fetch updates for split estimate
        let updates = [];
        if (userId && userType) {
            const Client = require('../models/client');
            let partner = await Client.getPartnerByUserId(userId);
            updates = await RequestUpdates.fetchAllSplitEstimateUpdates(5, id, null, partner?.id || 0, userId, userType);
        }
        
        res.send({status:1, message:"Split Estimate Details Fetched Successfully", splitEstimate, splitEstimateAttachments, splitEstimateRecipes, splitEstimateServices, otherInstallationSplitManagementSettings,currentFacilitySplitManagementSettings, updates});
    } catch (error) {
        console.log("error", error);
        res.send({status:0, message:"Server Error", error:error});
    }
}

const deleteSplitEstimate = async (req,res) => {
    try {
        const {split_estimate_id, targetFacilityId, currentFacilityId, userId} = req.body;
        const data = {
            status: 0,
            timestamp: moment().unix()
        }
        
        const splitEstimate = await SplitEstimateModel.updateSplitEstimate(data, split_estimate_id);
        
        // Add update entry
        if(splitEstimate && userId){
            const splitEstimateDetails = await SplitEstimateModel.getSplitEstimateById(split_estimate_id);
            const Client = require('../models/client');
            let clientDetails = await Client.getPartnerByUserId(userId);
            
            let splitEstimateUpdatesData = {
                split_estimate_id: split_estimate_id,
                partner_id: clientDetails?.id || 0,
                partner_name: clientDetails?.name || '',
                activity: `Split Estimate "${splitEstimateDetails?.name || ''}" has been deleted`,
                added_by: userId,
                timestamp: moment().unix(),
            }
            await RequestUpdates.addSplitEstimateUpdates(splitEstimateUpdatesData);
        }
        
        // Sync deletion to other installation if target facility is different from current
        if(targetFacilityId && targetFacilityId !== currentFacilityId){
            console.log(`Syncing split estimate deletion to facility_id: ${targetFacilityId}`);
            
            // Sync deletion (status update to 0) to other installation
            const syncResult = await SplitManagementModel.syncSplitEstimateStatusUpdateAcrossInstallations(
                data, 
                split_estimate_id, 
                targetFacilityId
            );

            if(syncResult.success){
                console.log(`Successfully synced deletion to other installation: ${syncResult.message}`);
            } else {
                console.log(`Failed to sync deletion to other installation: ${syncResult.message}`);
            }
        }
        
        res.send({status:1, message:"Split Estimate Deleted Successfully", splitEstimate});
    } catch (error) {
        console.log("error", error);
        res.send({status:0, message:"Server Error", error:error});
    }
}

const updateSplitEstimate = async (req,res) => {
    try {
        const {split_estimate_id,values,selectedRecipes,currentFacilityId,targetFacilityId,totalCost,userId} = req.body;
        const attachments = values?.avatarUrl;
        
        // Fetch old data before update for comparison
        const oldSplitEstimate = await SplitEstimateModel.getSplitEstimateById(split_estimate_id);
        const oldRecipes = await SplitEstimateModel.fetchAllSplitEstimateRecipes(split_estimate_id);
        const oldServices = await SplitEstimateModel.getSplitEstimateServicesBySplitEstimateId(split_estimate_id);
        
        const data={
           name: values?.name,
           to_facility_id: values?.to_facility_id || targetFacilityId,
           description: (values?.description || '').replace(/\r?\n/g, '\n'),
           description_lines: (values?.description || '') ? (values?.description || '').replace(/\r?\n/g, '\n').split('\n') : [],
           notes: (values?.notes || '').replace(/\r?\n/g, '\n'),
           notes_lines: (values?.notes || '') ? (values?.notes || '').replace(/\r?\n/g, '\n').split('\n') : [],
           timestamp: moment().unix(),
        //    total_cost:selectedRecipes.reduce((total, data) => total + (data?.total_cost  || 0), 0).toFixed(2),
           total_cost: parseFloat(totalCost).toFixed(2),
           status :1  
        }
        

        let total_cost =selectedRecipes.reduce((total, data) => total + (data?.total_cost  || 0), 0).toFixed(2)
        console.log('total_cost-----', total_cost)
        console.log('data-------', data)

        // Fetch existing split estimate to check isFromDesignOrder (design_order_id when from design order)
        const existingSplitEstimate = await SplitEstimateModel.getSplitEstimateById(split_estimate_id);
        const isFromDesignOrder = existingSplitEstimate?.isFromDesignOrder != null && existingSplitEstimate?.isFromDesignOrder !== '';

        const splitEstimate = await SplitEstimateModel.updateSplitEstimate(data,split_estimate_id);
        console.log('splitEstimateeeee', splitEstimate)
        
        // Build detailed activity message
        let notification_msg = ``;
        const currentTime = moment().unix();
        
        if (oldSplitEstimate && splitEstimate && userId) {
            // Compare name
            if (oldSplitEstimate.name !== data.name) {
                notification_msg += `The Split Estimate Name changed to <strong>${data.name}.</strong> `;
            }
            
            // Compare description
            if (oldSplitEstimate.description !== data.description) {
                notification_msg += `The Split Estimate description updated to <strong>${data.description || ''}.</strong> `;
            }
            
            // Compare facility
            if (oldSplitEstimate.to_facility_id != data.to_facility_id) {
                notification_msg += `The target facility has been updated. `;
            }
            
            // Compare total cost
            if (parseFloat(oldSplitEstimate.total_cost || 0).toFixed(2) !== parseFloat(totalCost).toFixed(2)) {
                notification_msg += `The total cost changed from <strong>$${parseFloat(oldSplitEstimate.total_cost || 0).toFixed(2)}</strong> to <strong>$${parseFloat(totalCost).toFixed(2)}.</strong> `;
            }
            
            // Compare recipes (products/formulas)
            // Convert Sequelize instances to plain objects for comparison
            const oldRecipesArray = Array.isArray(oldRecipes) ? oldRecipes.map(r => {
                const plain = r.dataValues || r;
                return {
                    id: plain.id,
                    recipe_id: plain.recipe_id,
                    product_name: plain.product_name || '',
                    recipe_name: plain.recipe_name || plain.name || '',
                    expected_cost: parseFloat(plain.expected_cost || 0),
                    split_percentage: parseFloat(plain.split_percentage || 0),
                    expected_install_labor_cost: parseFloat(plain.expected_install_labor_cost || 0)
                };
            }) : [];
            const newRecipesArray = Array.isArray(selectedRecipes) ? selectedRecipes.map(r => ({
                id: r?.id || null,
                recipe_id: r?.recipe_id || null,
                product_name: r?.product_name || '',
                name: r?.name || r?.recipe_name || '',
                expected_cost: parseFloat(r?.expected_cost || 0),
                split_percentage: parseFloat(r?.split_percentage || 0),
                expected_install_labor_cost: parseFloat(r?.expected_install_labor_cost || 0)
            })) : [];
            console.log('selectedRecipes---', selectedRecipes)
            console.log('oldRecipesArray---', oldRecipesArray)
            console.log('newRecipesArray---', newRecipesArray)
            
            // Helper function to match recipes - more robust matching
            const matchRecipe = (oldRecipe, newRecipe) => {
                // Match by recipe_id if both have it and it's not null
                if (oldRecipe.recipe_id && newRecipe.recipe_id && 
                    oldRecipe.recipe_id === newRecipe.recipe_id && 
                    oldRecipe.recipe_id !== null) {
                    return true;
                }
                if (oldRecipe.id && newRecipe.id && 
                    oldRecipe.id === newRecipe.id && 
                    oldRecipe.id !== null) {
                    return true;
                }
                // Match by product_name and recipe_name/name (case-insensitive, trimmed)
                const oldProductName = (oldRecipe.product_name || '').trim().toLowerCase();
                const newProductName = (newRecipe.product_name || '').trim().toLowerCase();
                const oldRecipeName = (oldRecipe.recipe_name || '').trim().toLowerCase();
                const newRecipeName = (newRecipe.name || '').trim().toLowerCase();
                
                if (oldProductName && newProductName && oldProductName === newProductName) {
                    // If recipe names match, it's the same recipe
                    if (oldRecipeName && newRecipeName && oldRecipeName === newRecipeName) {
                        return true;
                    }
                    // If both recipe names are empty/null and product names match, consider it a match
                    if (!oldRecipeName && !newRecipeName) {
                        return true;
                    }
                }
                return false;
            };
            
            // Track which new recipes have been matched to avoid duplicates
            const matchedNewRecipeIndices = new Set();
            
            // Check for removed recipes - only items that exist in old but not in new
            oldRecipesArray.forEach(oldRecipe => {
                let foundMatch = false;
                newRecipesArray.forEach((newRecipe, index) => {
                    if (matchRecipe(oldRecipe, newRecipe)) {
                        foundMatch = true;
                        matchedNewRecipeIndices.add(index);
                        
                        // Check for quantity/cost changes only if values actually changed
                        if (oldRecipe.expected_cost.toFixed(2) !== newRecipe.expected_cost.toFixed(2)) {
                            notification_msg += `Expected cost of '${oldRecipe.product_name || oldRecipe.recipe_name || ''}' changed from <strong>$${oldRecipe.expected_cost.toFixed(2)}</strong> to <strong>$${newRecipe.expected_cost.toFixed(2)}.</strong> `;
                        }
                        if (oldRecipe.split_percentage.toFixed(2) !== newRecipe.split_percentage.toFixed(2)) {
                            notification_msg += `Split percentage of '${oldRecipe.product_name || oldRecipe.recipe_name || ''}' changed from <strong>${oldRecipe.split_percentage.toFixed(2)}%</strong> to <strong>${newRecipe.split_percentage.toFixed(2)}%.</strong> `;
                        }
                        if (oldRecipe.expected_install_labor_cost.toFixed(2) !== newRecipe.expected_install_labor_cost.toFixed(2)) {
                            notification_msg += `Install labor cost of '${oldRecipe.product_name || oldRecipe.recipe_name || ''}' changed from <strong>$${oldRecipe.expected_install_labor_cost.toFixed(2)}</strong> to <strong>$${newRecipe.expected_install_labor_cost.toFixed(2)}.</strong> `;
                        }
                        if (oldRecipe.product_name !== newRecipe.product_name) {
                            notification_msg += `Product name changed from '${oldRecipe.product_name}' to '${newRecipe.product_name}'. `;
                        }
                    }
                });
                
                if (!foundMatch) {
                    notification_msg += `Product '${oldRecipe.product_name || oldRecipe.recipe_name || ''}' removed from the Split Estimate. `;
                }
            });
            
            // Check for added recipes - only items that exist in new but not in old (and weren't already matched)
            newRecipesArray.forEach((newRecipe, index) => {
                if (!matchedNewRecipeIndices.has(index)) {
                    const oldRecipe = oldRecipesArray.find(item => matchRecipe(item, newRecipe));
                    if (!oldRecipe) {
                        notification_msg += `New product '${newRecipe.product_name || newRecipe.name || ''}' added to the Split Estimate. `;
                    }
                }
            });
            
            // Compare services
            // Convert Sequelize instances to plain objects for comparison
            const oldServicesArray = Array.isArray(oldServices) ? oldServices.map(s => {
                const plain = s.dataValues || s;
                return {
                    id: plain.id,
                    labour_cost_service_id: plain.labour_cost_service_id,
                    name: plain.name || '',
                    quantity: parseFloat(plain.quantity || 0),
                    unit_cost: parseFloat(plain.unit_cost || 0),
                    total: parseFloat(plain.total || 0)
                };
            }) : [];
            const incomingServices = Array.isArray(values?.split_services) ? values.split_services.map(s => ({
                labour_cost_service_id: s.labour_cost_service_id,
                name: s.name || '',
                quantity: parseFloat(s.quantity || 0),
                unit_cost: parseFloat(s.unit_cost || 0),
                total: parseFloat(s.total || 0)
            })) : [];
            
            // Track which new services have been matched to avoid duplicates
            const matchedNewServiceIndices = new Set();
            
            // Check for removed services - only items that exist in old but not in new
            oldServicesArray.forEach(oldService => {
                let foundMatch = false;
                incomingServices.forEach((newService, index) => {
                    if (oldService.labour_cost_service_id === newService.labour_cost_service_id) {
                        foundMatch = true;
                        matchedNewServiceIndices.add(index);
                        
                        // Check for quantity/cost changes only if values actually changed
                        if (oldService.quantity.toFixed(2) !== newService.quantity.toFixed(2)) {
                            notification_msg += `Quantity of service '${oldService.name || ''}' changed from <strong>${oldService.quantity.toFixed(2)}</strong> to <strong>${newService.quantity.toFixed(2)}.</strong> `;
                        }
                        if (oldService.unit_cost.toFixed(2) !== newService.unit_cost.toFixed(2)) {
                            notification_msg += `Unit cost of service '${oldService.name || ''}' changed from <strong>$${oldService.unit_cost.toFixed(2)}</strong> to <strong>$${newService.unit_cost.toFixed(2)}.</strong> `;
                        }
                        if (oldService.total.toFixed(2) !== newService.total.toFixed(2)) {
                            notification_msg += `Total cost of service '${oldService.name || ''}' changed from <strong>$${oldService.total.toFixed(2)}</strong> to <strong>$${newService.total.toFixed(2)}.</strong> `;
                        }
                    }
                });
                
                if (!foundMatch) {
                    notification_msg += `Service '${oldService.name || ''}' removed from the Split Estimate. `;
                }
            });
            
            // Check for added services - only items that exist in new but not in old (and weren't already matched)
            incomingServices.forEach((newService, index) => {
                if (!matchedNewServiceIndices.has(index)) {
                    const oldService = oldServicesArray.find(item => 
                        item.labour_cost_service_id === newService.labour_cost_service_id
                    );
                    if (!oldService) {
                        notification_msg += `New service '${newService.name || ''}' added to the Split Estimate. `;
                    }
                }
            });
        }
        
        // Add detailed update entry if there are changes
        if (notification_msg && notification_msg.trim() && splitEstimate && userId) {
            const Client = require('../models/client');
            const { empty } = require('../Helpers/Common');
            let clientDetails = await Client.getPartnerByUserId(userId);
            
            if (!empty(notification_msg)) {
                let splitEstimateUpdatesData = {
                    split_estimate_id: split_estimate_id,
                    partner_id: clientDetails?.id || 0,
                    partner_name: clientDetails?.name || '',
                    activity: notification_msg.trim(),
                    added_by: userId,
                    timestamp: currentTime,
                }
                await RequestUpdates.addSplitEstimateUpdates(splitEstimateUpdatesData);
            }
        } else if (splitEstimate && userId) {
            // Fallback to simple message if no detailed changes detected
            const Client = require('../models/client');
            let clientDetails = await Client.getPartnerByUserId(userId);
            
            let splitEstimateUpdatesData = {
                split_estimate_id: split_estimate_id,
                partner_id: clientDetails?.id || 0,
                partner_name: clientDetails?.name || '',
                activity: `Split Estimate "${values?.name || ''}" has been updated`,
                added_by: userId,
                timestamp: moment().unix(),
            }
            await RequestUpdates.addSplitEstimateUpdates(splitEstimateUpdatesData);
        }
        
        // Store updated split estimate data for syncing
        const UpdateSplitData = splitEstimate;
        
        // Build services data from incoming values (behaves like recipes)
        const incomingServices = Array.isArray(values?.split_services) ? values.split_services : [];
        let servicesData = [];
        if (incomingServices.length > 0) {
            for (let i = 0; i < incomingServices.length; i++) {
                const service = incomingServices[i];
                const serviceData = {
                    labour_cost_service_id: service.labour_cost_service_id,
                    name: service.name,
                    quantity: service.quantity || 0,
                    total: service.total || 0,
                    unit_cost: service.unit_cost || 0,
                    taken: service.taken || 0,
                    job_cost: service.job_cost || 0,
                    jobcost_quantity: service.jobcost_quantity || 0.00,
                    jobcost_total_cost: service.jobcost_total_cost || 0.00,
                    split_estimate_id: split_estimate_id,
                    complete: service.complete || 0,
                    status: service.status || 1
                };
                servicesData.push(serviceData);
            }
        }
        
        let existingImagesByAttachmentId = {};
        if(splitEstimate){
            // When from design order: preserve edited PDF attachment images (same as editRequest) — fetch and delete only DB rows
            if (isFromDesignOrder) {
                const existingAttachments = await SplitEstimateModel.getSplitEstimateAttachmentsBySplitEstimateId(split_estimate_id);
                if (existingAttachments && existingAttachments.length > 0) {
                    const list = Array.isArray(existingAttachments) ? existingAttachments : (existingAttachments.map ? existingAttachments.map(a => a.get ? a.get({ plain: true }) : a) : []);
                    for (let idx = 0; idx < list.length; idx++) {
                        const att = list[idx];
                        const attId = att.id;
                        const imgs = await getRequestAttachmentImagesByDocumentId(attId, 'split_estimate');
                        if (imgs && imgs.length > 0) existingImagesByAttachmentId[attId] = imgs;
                        await deleteRequestAttachmentImagesByDocumentId(attId, 'split_estimate');
                    }
                }
            }
            await SplitEstimateModel.deleteAllSplitEstimateAttachments(split_estimate_id);
            await SplitEstimateModel.deleteSplitEstimateRecipes(split_estimate_id);
            await SplitEstimateModel.deleteSplitEstimateServices(split_estimate_id);
        }
        
        let attachmentsData = [];
        if(attachments && Array.isArray(attachments) && attachments.length > 0){
            for(let i=0;i<attachments.length;i++){
                const attachment = attachments[i];
                const attachmentData = {
                    url: attachment.url,
                    file_type: attachment.file_type,
                    split_estimate_id: split_estimate_id,
                    timestamp: moment().unix(),
                }
                const attachmentResult = await SplitEstimateModel.addSplitEstimateAttachments(attachmentData);
                const newAttachmentId = attachmentResult?.id ?? (attachmentResult?.dataValues?.id);
                if (newAttachmentId) {
                    // When from design order: copy edited PDF images by existing attachment id (same as editRequest)
                    const savedImages = isFromDesignOrder && (attachment.id != null && existingImagesByAttachmentId[attachment.id]) ? existingImagesByAttachmentId[attachment.id] : null;
                    if (savedImages && savedImages.length > 0) {
                        const timestamp = moment().unix();
                        for (const img of savedImages) {
                            const row = img.get ? img.get({ plain: true }) : img;
                            await addRequestAttachmentImage({
                                document_id: newAttachmentId,
                                document_source: 'split_estimate',
                                image_url: row.image_url,
                                page_number: row.page_number,
                                file_size: row.file_size != null ? row.file_size : 0,
                                timestamp: timestamp,
                                status: 1
                            });
                        }
                        console.log(`updateSplitEstimate: copied ${savedImages.length} attachment images to split estimate attachment ${newAttachmentId}`);
                    } else {
                        // No saved images: convert existing PDF to PNG (including PDFs added before conversion)
                        // const isPdfFile =
                        //     (attachment.file_type === 'application/pdf' || attachment.file_type === 'pdf') ||
                        //     (attachment.extension && String(attachment.extension).toLowerCase() === 'pdf') ||
                        //     (attachment.url && String(attachment.url).toLowerCase().endsWith('.pdf')) ||
                        //     (attachment.name && String(attachment.name).toLowerCase().endsWith('.pdf'));
                        // if (isPdfFile) {
                        //     try {
                        //         await convertPdfToPngHelper(newAttachmentId, SplitEstimateModel.getSplitEstimateAttachmentByIdForConversion, 'split_estimate');
                        //         console.log(`PDF conversion completed for split estimate document ID: ${newAttachmentId}`);
                        //     } catch (conversionError) {
                        //         console.error(`Error converting PDF for split estimate document ${newAttachmentId}:`, conversionError);
                        //     }
                        // }
                    }
                }
                attachmentsData.push(attachmentData);
            }
        }

        let recipesData = [];
        if(selectedRecipes && Array.isArray(selectedRecipes) && selectedRecipes.length > 0){
            for(let i=0;i<selectedRecipes.length;i++){
                const recipe = selectedRecipes[i];
                const recipeData = {
                    recipe_name: recipe.name,
                    expected_cost: recipe.expected_cost || 0,
                    recipe_id: recipe?.recipe_id || null,
                    split_estimate_id: split_estimate_id,
                    product_name: recipe.product_name,
                    total_cost: recipe.total_cost || 0,
                    split_percentage: recipe.split_percentage || 0,
                    expected_install_labor_cost: recipe.expected_install_labor_cost || 0,
                }
                const recipeResult = await SplitEstimateModel.addSplitEstimateRecipes(recipeData);
                recipesData.push(recipeData);
                console.log('recipeData---', recipeData)
            }
        }

        // Re-add split services from incoming values
        if (servicesData && servicesData.length > 0) {
            for (let i = 0; i < servicesData.length; i++) {
                const svc = servicesData[i];
                await SplitEstimateModel.addSplitEstimateServices(svc);
            }
        }

        // Sync update to other installation if target facility is different from current
       
        // if(targetFacilityId && targetFacilityId !== currentFacilityId){
            if(targetFacilityId){
            console.log(`Syncing split estimate update to facility_id: ${targetFacilityId}`);
            
            // Sync update to other installation
            const syncResult = await SplitManagementModel.syncSplitEstimateUpdateAcrossInstallations(
                UpdateSplitData, 
                attachmentsData, 
                recipesData,
                servicesData,
                split_estimate_id, 
                targetFacilityId
            );

            if(syncResult.success){
                console.log(`Successfully synced update to other installation: ${syncResult.message}`);
            } else {
                console.log(`Failed to sync update to other installation: ${syncResult.message}`);
            }
        }

        res.send({status:1, message:"Split Estimate Updated Successfully", splitEstimate});
    }
     catch (error) {
        console.log("error", error);
        res.send({status:0, message:"Server Error", error:error});
    }
}

const updateSplitEstimateStatus = async (req,res) => {
    try {
        const {split_estimate_id,status,reason,targetFacilityId,currentFacilityId,userId} = req.body;
        const data = {
            status: status,
            reason: reason,
            timestamp: moment().unix()
        }
        
        const splitEstimate = await SplitEstimateModel.updateSplitEstimate(data,split_estimate_id);
        
        // Add update entry
        if(splitEstimate && userId){
            const splitEstimateDetails = await SplitEstimateModel.getSplitEstimateById(split_estimate_id);
            const Client = require('../models/client');
            let clientDetails = await Client.getPartnerByUserId(userId);
            
            let statusText = status === 1 ? 'Open' : status === 2 ? 'Approved' : status === 3 ? 'Approved' : status === 4 ? 'Draft' : status === 5 ? 'Closed' : status === 6 ? 'Rejected' : 'Unknown';
            let activityMsg = `Split Estimate "${splitEstimateDetails?.name || ''}" status has been updated to ${statusText}`;
            if(reason && status === 6){
                activityMsg = `Split Estimate "${splitEstimateDetails?.name || ''}" has been rejected. Reason: ${reason}`;
            }
            
            let splitEstimateUpdatesData = {
                split_estimate_id: split_estimate_id,
                partner_id: clientDetails?.id || 0,
                partner_name: clientDetails?.name || '',
                activity: activityMsg,
                added_by: userId,
                timestamp: moment().unix(),
            }
            await RequestUpdates.addSplitEstimateUpdates(splitEstimateUpdatesData);
        }
        
        // Sync status update to other installation if target facility is different from current
        // if(targetFacilityId && targetFacilityId !== currentFacilityId){
            if(targetFacilityId ){
            console.log(`Syncing split estimate status update to facility_id: ${targetFacilityId}`);
            
            // Sync status update to other installation
            const syncResult = await SplitManagementModel.syncSplitEstimateStatusUpdateAcrossInstallations(
                data, 
                split_estimate_id, 
                targetFacilityId
            );

            if(syncResult.success){
                console.log(`Successfully synced status update to other installation: ${syncResult.message}`);
            } else {
                console.log(`Failed to sync status update to other installation: ${syncResult.message}`);
            }
        }
        
        res.send({status:1, message:"Split Estimate Status Updated Successfully", splitEstimate});
    } catch (error) {
        console.log("error", error);
        res.send({status:0, message:"Server Error", error:error});
    }
}

const convertSplitEstimateToEstimate = async (req,res) => {
    try {
        const {split_estimate_id,userId,targetFacilityId,currentFacilityId,isSalesOrder} = req.body;
        
        // Fetch split estimate details
        const splitEstimateDetails = await SplitEstimateModel.getSplitEstimateById(split_estimate_id);
        if (!splitEstimateDetails) {
            return res.send({status: 0, message: "Split Estimate not found"});
        }

        // Fetch split estimate recipes with product details
        const splitRecipes = await SplitEstimateModel.fetchAllSplitEstimateRecipes(split_estimate_id);
        
        // Fetch split estimate attachments
        const splitAttachments = await SplitEstimateModel.getSplitEstimateAttachmentsBySplitEstimateId(split_estimate_id);
        
        // Fetch split estimate services
        const splitServices = await SplitEstimateModel.getSplitEstimateServicesforRequest(split_estimate_id);
        
        // Prepare request data for split order quotation
        let currentDate = moment().unix();
        let requestdata = {
            name: splitEstimateDetails.name,
            description: splitEstimateDetails.description,
            quotation: isSalesOrder ? 0 : 1, // Set as quotation
            status:isSalesOrder ? 2 : 8, // Quotation status
            quotation_status: 2, // Approved quotation
            type: 2,
            timestamp: currentDate,
            added_by: userId,
            origin_facility_id: splitEstimateDetails?.origin_facility_id,
            to_facility_id: splitEstimateDetails?.to_facility_id,
            client_approve: 0,
            send_to_client: 0,
            min_payment_status: 0,
            welcome_message: false,
            subject: null,
            email_content: null,
            notes: "",
            markup_type: 2,
            project_type: null,
            project_category: null, // Set as split order category
            community: null,
            submission_deadline: currentDate,
            participation_ends: currentDate,
            installation_start_date: null,
            installation_end_date: null,
            start_date: currentDate,
            created_at: currentDate,
            isReview: 0,
            catalog_type: null,
            no_charge_type: null,
            map_service: null,
            is_split_order: 1, // Mark as split order
            facility_type: splitEstimateDetails?.to_facility_id, // Target facility
            for_parent_facility: 0 // This is the main order, not a child order
        };

        // Create the request/quotation
        const requestId = await RequestModel.addRequest(requestdata);
        if (!requestId) {
            return res.send({status: 0, message: "Failed to create quotation"});
        }

        // Add split estimate attachments to request attachments if any exist
        if (splitAttachments && splitAttachments.length > 0) {
            console.log(`Adding ${splitAttachments.length} split estimate attachments to request ${requestId}`);
            
            for (const attachment of splitAttachments) {
                try {
                    // Extract filename from URL or use a default name
                    const url = attachment.url || '';
                    const fileName = url.split('/').pop() || `attachment_${attachment.id}`;
                    const fileExtension = fileName.split('.').pop() || 'img';
                    
                    const requestAttachmentData = {
                        name: url,
                        request_id: requestId,
                        extension: fileExtension,
                        file_size: 2, // Default file size
                        file_type: attachment.file_type || 'img',
                        approved: 0, 
                        status: 1,
                        added_by: userId,
                        timestamp: currentDate
                    };
                    
                    const attachmentId = await RequestModel.addRequestAttachments(requestAttachmentData);
                    console.log(`Successfully added attachment ${attachmentId} to request ${requestId}`);
                    
                } catch (attachmentError) {
                    console.log(`Error adding attachment to request:`, attachmentError);
                    // Continue with other attachments even if one fails
                }
            }
        }

        const currentFacilitySplitManagementSettings = await SplitManagementModel.getAllSplitManagementSettings();
        console.log('currentFacilitySplitManagementSettings', currentFacilitySplitManagementSettings)
        // Get all products from targeted facility using model function
        const allTargetFacilityProducts = await SplitManagementModel.getAllProductsFromSpecificFacility(splitEstimateDetails.to_facility_id, true);
        console.log('allTargetFacilityProducts----', allTargetFacilityProducts)
        if (allTargetFacilityProducts?.length > 0) {
        // Filter products that are available in selected recipes
        const recipeProductIds = splitRecipes.map(recipe => recipe.product_id).filter(id => id !== null);
        const availableRecipeProducts = allTargetFacilityProducts.filter(product => 
            recipeProductIds.includes(product.id)
        );
        
        console.log('Available recipe products in target facility:', availableRecipeProducts.length);
        
        // Combine product data with recipe data for customer order
        const productsForOrder = availableRecipeProducts.map(product => {
            const matchingRecipe = splitRecipes.find(recipe => recipe.product_id === product.id);
            return {
                ...product,
                recipeData: matchingRecipe,
                // Prepare data for customer order
                orderData: {
                    product_id: product.id,
                    product_name: product.name,
                    expected_cost: matchingRecipe?.expected_cost || 0,
                    split_percentage: matchingRecipe?.split_percentage || 0,
                    recipe_id: matchingRecipe?.recipe_id || null,
                    recipe_name: matchingRecipe?.recipe_name || null,
                    expected_install_labor_cost: matchingRecipe?.expected_install_labor_cost || 0,
                    timestamp: currentDate,
                    expected_cost_with_percentage: (() => {
                        const expectedCost = matchingRecipe?.expected_cost || 0;
                        const splitPercentage = matchingRecipe?.split_percentage || 0;
                        const splitAmount = expectedCost * (splitPercentage / 100);
                        return parseFloat((expectedCost + splitAmount).toFixed(2));
                    })(),
                    incoming_split_percentage: currentFacilitySplitManagementSettings[0]?.incoming_percentage || 0,
                }
            };
        });
        
        console.log('Products prepared for customer order:', productsForOrder);

        // Calculate installation end date from productsForOrder lead times
        let installationEndDate = null;
        const productsWithLeadTime = productsForOrder.filter(product => product.lead_time && product.lead_time > 0);
        
        if (productsWithLeadTime.length > 0) {
            const highestLeadTime = Math.max(...productsWithLeadTime.map(product => product.lead_time));
            installationEndDate = moment().add(highestLeadTime, 'days').unix();
            
            // Update request with installation end date
            await RequestModel.updateRequets(requestId, {
                participation_ends: installationEndDate
            });
        }

        // Calculate total amount from all products
        const productTotalAmount = productsForOrder.reduce((total, product) => {
            const expectedCostWithPercentage = product.orderData.expected_cost_with_percentage || 0;
            const incomingSplitPercentage = product.orderData.incoming_split_percentage || 0;
            const expectedInstallLaborCost = product.orderData.expected_install_labor_cost || 0;
            
            // Calculate incoming split amount as percentage of expected_cost_with_percentage
            const incomingSplitAmount = expectedCostWithPercentage * (incomingSplitPercentage / 100);
            const productTotal = expectedCostWithPercentage + incomingSplitAmount + expectedInstallLaborCost;
            
            console.log(`Product ${product.orderData.product_name}: expected_cost_with_percentage=${expectedCostWithPercentage}, incoming_split_percentage=${incomingSplitPercentage}%, incoming_split_amount=${incomingSplitAmount}, expected_install_labor_cost=${expectedInstallLaborCost}, total=${productTotal}`);
            
            return total + productTotal;
        }, 0);

        // Calculate total amount from all services
        const serviceTotalAmount = splitServices?.length > 0 ? splitServices.reduce((total, service) => {
            const serviceTotal = service.total || 0;
            console.log(`Service ${service.name || service.labour_cost_service_id}: total=${serviceTotal}`);
            return total + serviceTotal;
        }, 0) : 0;

        // Calculate grand total (products + services)
        const totalAmount = productTotalAmount + serviceTotalAmount;

        console.log('Calculated product total amount:', productTotalAmount);
        console.log('Calculated service total amount:', serviceTotalAmount);
        console.log('Calculated grand total amount:', totalAmount);

        let orderData = {
            total: totalAmount,
            grandTotal: totalAmount,
            tax_amount: 0,
            tax_category: null,
            budget: totalAmount,
            extra_discount: 0,
            request_id: requestId,
            timestamp: currentDate,
            sub_total: totalAmount,
            tax: 0,
            status: 1
        };
        console.log('orderData1234-CustomerOrder-----------', orderData);
        let resultData = await CustomerOrderModel.createCustomerOrder(orderData)
        let requestProduct = {};
        if (productsForOrder?.length > 0) {
            let index = 0;
            for (const row of productsForOrder) {
                index++;
                let rowQuantity = row.quantity ? row.quantity : 1;
                // let rowDiscount = row.discount ? row.discount : 0
                let rowDiscount = 0
                let rowAdjustment = row?.adjustment ? row?.adjustment : 0
                // Calculate individual product total
                const expectedCostWithPercentage = row.orderData.expected_cost_with_percentage || 0;
                const incomingSplitPercentage = row.orderData.incoming_split_percentage || 0;
                const expectedInstallLaborCost = row.orderData.expected_install_labor_cost || 0;
                const splitPercentage = row.orderData.split_percentage || 0;
                
                // Calculate incoming split amount as percentage of expected_cost_with_percentage
                const incomingSplitAmount = expectedCostWithPercentage * (incomingSplitPercentage / 100);
                const productTotal = expectedCostWithPercentage + incomingSplitAmount + expectedInstallLaborCost;
                console.log('productTotal------', productTotal)
    
                requestProduct['order_id'] = resultData
                requestProduct['product_index'] = index
                requestProduct['product_id'] = row.id || null,
                requestProduct['product_name'] = row.name,
                requestProduct['product_notes'] = row.product_notes || null,
                requestProduct['install_notes'] = row.install_notes || null,
                requestProduct['service_notes'] = row.service_notes || null,
                requestProduct['product_price'] = row.price || 0.00,
                requestProduct['product_retail_price'] = productTotal,
                requestProduct['product_markup'] = row.markup ? row.markup : null,
                requestProduct['product_qty'] = rowQuantity,
                requestProduct['location_quantity'] = row.locationQuantity||1,
                requestProduct['product_sub_total'] = productTotal,
                requestProduct['product_tax'] = 0,
                requestProduct['product_total'] = productTotal,
                requestProduct['workflow'] = row.workflow,
                requestProduct['discount'] = rowDiscount,
                requestProduct['adjustment'] = rowAdjustment,
                requestProduct['timestamp'] = currentDate,
                requestProduct['status'] = row.status
                requestProduct['markAdjType'] = row.markAdjType || 1
                requestProduct['map_service'] = row?.fromMapServices ? 1 : 0
                requestProduct['allLocationSame'] = 1
                requestProduct['isAdditionalProduct'] = row?.isAdditionalProduct ? 1 : 0
                requestProduct['is_single_card'] = 1
                requestProduct['install_cost'] = row?.install_cost || null
                requestProduct['facility_id'] = row?.facility_id  || FACILITY_ID
                requestProduct['split_percentage'] =   splitPercentage  || 0
                requestProduct['incoming_split_percentage'] = incomingSplitPercentage || 0
                requestProduct['expected_formula_price'] = row?.expected_cost || 0
      
                let response = await CustomerOrderProduct.createCustomerOrder(requestProduct)
              }

       }
    }

        // Add split estimate services to request services if any exist
        if (splitServices && splitServices.length > 0) {
            console.log(`Adding ${splitServices.length} split estimate services to request ${requestId}`);
            
            for (const service of splitServices) {
                try {
                    let requestService = {};
                    let serviceQuantity = service.quantity ? service.quantity : 1;
                    
                    requestService['product_index'] = 0;
                    requestService['request_id'] = requestId;
                    requestService['labour_cost_service_id'] = service.labour_cost_service_id;
                    requestService['recipe_id'] = null;
                    requestService['product_id'] = null;
                    requestService['qty'] = serviceQuantity;
                    requestService['unit_cost'] = service.unit_cost || service.total;
                    requestService['markup'] = service?.markup || 0;
                    requestService['total_cost'] = service.total;
                    requestService['rfp'] = 0;
                    requestService['map_service'] = 0;
                    requestService['jobcost_unit_cost'] = 0;
                    requestService['jobcost_quantity'] = service?.jobcost_quantity ? service?.jobcost_quantity : 0;
                    requestService['jobcost_total_cost'] = service?.jobcost_total_cost ? service?.jobcost_total_cost : 0;
                    requestService['is_dos'] = 1;
                    requestService['makeAsTask'] = service?.makeAsTask ? 1 : 0;
                    requestService['makeInstallCard'] = service?.makeInstallCard ? 1 : 0;
                    
                    let response = await RequestModel.addRequestServices(requestService);
                    console.log(`Successfully added service ${service.labour_cost_service_id} to request ${requestId}`);
                    
                } catch (serviceError) {
                    console.log(`Error adding service to request:`, serviceError);
                    // Continue with other services even if one fails
                }
            }
        }
        let reqActivityMsg = `${isSalesOrder 
            ? 'Sales Order has been converted from Split Estimate' 
            : 'Estimate has been converted from Split Estimate'
          }`;          
        if(requestId){
            let requestActivity = {}
          requestActivity['request_id'] = requestId;
          requestActivity['activity'] = reqActivityMsg
          requestActivity['added_by'] = userId
          requestActivity['timestamp'] = currentDate
          requestActivity['status'] = 1
          let reqActivityId = await RequestActivity.addRequestUpdate(requestActivity)
          console.log('reqActivityIddd', reqActivityId)
        
        }

        // Add update entry for conversion
        if(userId){
            const Client = require('../models/client');
            let clientDetails = await Client.getPartnerByUserId(userId);
            
            let splitEstimateUpdatesData = {
                split_estimate_id: split_estimate_id,
                partner_id: clientDetails?.id || 0,
                partner_name: clientDetails?.name || '',
                activity: `Split Estimate "${splitEstimateDetails?.name || ''}" has been converted to ${isSalesOrder ? 'Sales Order' : 'Quotation'}`,
                added_by: userId,
                timestamp: moment().unix(),
            }
            await RequestUpdates.addSplitEstimateUpdates(splitEstimateUpdatesData);
        }
        
        // Update split estimate status to indicate it's been converted
        const updateData = {
            status: 4, // Mark as converted
            timestamp: currentDate
        };
        
        const splitEstimate = await SplitEstimateModel.updateSplitEstimate(updateData, split_estimate_id);

        if(targetFacilityId && splitEstimate ){
            console.log(`Syncing split estimate status update to facility_id: ${targetFacilityId}`);
            
            // Sync status update to other installation
            const syncResult = await SplitManagementModel.syncSplitEstimateStatusUpdateAcrossInstallations(
                updateData, 
                split_estimate_id, 
                targetFacilityId
            );

            if(syncResult.success){
                console.log(`Successfully synced status update to other installation: ${syncResult.message}`);
            } else {
                console.log(`Failed to sync status update to other installation: ${syncResult.message}`);
            }
        }
        
        res.send({
            status: 1, 
            message: "Split Estimate converted to quotation successfully", 
            request_id: requestId,
            split_estimate_id: split_estimate_id,
            isSalesOrder: isSalesOrder || false
        });
        
    } catch (error) {
        console.log("error", error);
        res.send({status:0, message:"Server Error", error:error.message});
    }
}


const updateProductAddedStatus = async (req, res) => {
    try {
        const { selectedRecipeId,targetFacilityId,product_id } = req.body;
        
        if (!selectedRecipeId) {
            return res.send({ status: 0, message: 'Selected Recipe ID is required' });
        }
        const data = {
            product_added: 1,
            product_id: product_id
        }

        const result = await SplitEstimateModel.updateProductAddedStatus(data,selectedRecipeId);

        if(targetFacilityId && result ){
            console.log(`Syncing split estimate product status update to facility_id: ${targetFacilityId}`);
            // Sync status update to other installation
            const split_estimate_id = result?.split_estimate_id;
            const recipe_id = result?.recipe_id;
            const syncResult = await SplitManagementModel.syncSplitEstimateProductAddedStatusUpdateAcrossInstallations(
                data, 
                split_estimate_id, 
                targetFacilityId,
                recipe_id
            );

            if(syncResult.success){
                console.log(`Successfully synced status update to other installation: ${syncResult.message}`);
            } else {
                console.log(`Failed to sync status update to other installation: ${syncResult.message}`);
            }
        }
        
        if (result) {
            // Check if all products are added and update split estimate status to 5
            const split_estimate_id = result?.split_estimate_id;
            if (split_estimate_id) {
                // Get all recipes for this split estimate
                const allRecipes = await SplitEstimateModel.fetchAllSplitEstimateRecipes(split_estimate_id);
                
                if (allRecipes && allRecipes.length > 0) {
                    // Check if all recipes have product_added = 1
                    const allProductsAdded = allRecipes.every(recipe => recipe.product_added === 1);
                    
                    if (allProductsAdded) {
                        console.log(`All products added for split estimate ${split_estimate_id}. Updating status to 5.`);
                        
                        // Update split estimate status to 5 (Products Added Successfully)
                        const statusData = {
                            status: 5,
                            timestamp: moment().unix()
                        };
                        
                        const statusUpdateResult = await SplitEstimateModel.updateSplitEstimate(statusData, split_estimate_id);
                        
                        if (statusUpdateResult) {
                            console.log(`Split estimate ${split_estimate_id} status updated to 5 successfully`);
                            
                            // Sync status update to other installation if needed
                            if (targetFacilityId) {
                                const statusSyncResult = await SplitManagementModel.syncSplitEstimateStatusUpdateAcrossInstallations(
                                    statusData, 
                                    split_estimate_id, 
                                    targetFacilityId
                                );

                                if (statusSyncResult.success) {
                                    console.log(`Successfully synced status update to other installation: ${statusSyncResult.message}`);
                                } else {
                                    console.log(`Failed to sync status update to other installation: ${statusSyncResult.message}`);
                                }
                            }
                        } else {
                            console.log(`Failed to update split estimate ${split_estimate_id} status to 5`);
                        }
                    }
                }
            }
            
            res.send({ status: 1, message: 'Product added status updated successfully' });
        } else {
            res.send({ status: 0, message: 'Failed to update product added status' });
        }
    } catch (error) {
        console.log("Update product added status error - ", error);
        res.send({ status: 500, message: 'Error', error: error });
    }
};

module.exports = {
    addSplitEstimate,
    fetchAllSplitEstimates,
    fetchAllSplitEstimateDetails,
    deleteSplitEstimate,
    updateSplitEstimate,
    updateSplitEstimateStatus,
    updateProductAddedStatus,
    convertSplitEstimateToEstimate
}