const Resp = require("./helper/response");
const Info = require("./helper/info");
const Log = require("./helper/log");
const imap = require("imap");
imap.debug = console.log;
const { simpleParser } = require("mailparser");
const fs = require("fs");
const path = require("path");
const serverModel = require("./model/servermodel");
var POP3Client = require("mailpop3");
const emailOperation = require('./emailOperation');
const axios = require('axios');
const qs = require('qs');
const MAX_RETRIES = 3;
const RETRY_DELAY_MS = 2000;

class mailOperation {
    processPop3Mail(data, callback) {
        Log.incErrorLog("pop3");
    }

    processExchange(data, callback) {
        Log.incErrorLog("exchange");
    }

    async processIMAP(data, callback) {
        Log.incErrorLog(`Imap Process Started`);    
        try {
            // let securityProtocol = ''
            // if (data.security_protocol == "TLS") {
            //     securityProtocol = 'TLS';
            // } else if (data.security_protocol == "SSL") {
            //     securityProtocol = 'SSL';
            // } else {
            //     securityProtocol = false;
            // }
            const isTLS = data.security_protocol === 'TLS' || data.security_protocol === 'SSL';
            const imapConfig = {
                user: data.incoming_user_name,
                // password: data.incoming_password,
                host: data.incoming_mail_server,
                port: data.incoming_mail_server_port,
                tls: isTLS,
                tlsOptions: {
                    rejectUnauthorized: false,
                },
            };

            if (data.is_auth_enable) {

                Log.incErrorLog(`Using XOAUTH2 for ${data.incoming_user_name}`);
                // let base64Encoded = Buffer.from([
                //     `user=${data.incoming_user_name}`,
                //     `auth=Bearer ${data.token}`,
                //     '',
                //     ''
                // ].join('\x01'), 'utf-8').toString('base64');
                let base64Encoded = Buffer.from([`user=${data.incoming_user_name}`, `auth=Bearer ${data.token}`, '', ''].join('\x01'), 'utf-8').toString('base64');
                imapConfig.xoauth2 = base64Encoded;
            } else {
                imapConfig.password = data.incoming_password;
            }

            // if (data.is_auth_enable) {
            //     let base64Encoded = Buffer.from([`user=${data.incoming_user_name}`, `auth=Bearer ${data.token}`, '', ''].join('\x01'), 'utf-8').toString('base64');
            //     imapConfig.xoauth2 = base64Encoded
            // } else {
            //     imapConfig.password = data.incoming_password;
            // }
            let retries = 0;

            const tryConnect = () => {
                return new Promise((resolve, reject) => {
                    const imapConnection = new imap(imapConfig);
                    Log.incErrorLog(`Connecting to IMAP server ${data.incoming_mail_server} with user ${data.incoming_user_name}`);
                    // Log.incErrorLog(`Connecting to IMAP server ${data.incoming_mail_server} with user ${data.incoming_user_name} and password ${data.incoming_password}`);
                    Log.incErrorLog(`Connecting to IMAP server ${data.incoming_mail_server} with user ${data.incoming_user_name} and security protocol ${data.security_protocol}`);


                    imapConfig.debug = (msg) => {
                        console.log(`IMAP DEBUG (${incoming_user_name}): ${msg}`);
                    };

                    imapConnection.once("ready", () => {
                        Log.incErrorLog("Connected to IMAP server " + data.incoming_mail_server);


                        imapConnection.openBox("INBOX", false, (err, mailbox) => {
                            if (err) {
                                callback(`Error opening mailbox: ${err}`, null);
                            }

                            const dateString = data.dont_read_mail_before;

                            const dont_read_unread_mail = data.dont_read_unread_mail;

                            if (dont_read_unread_mail == "1") {
                                Log.incErrorLog(`dont_read_unread_mail is enabled for ${data.incoming_user_name}`);
                                serverModel.getLastReadDate(data.queue_id).then((result) => {
                                    if (result.status) {
                                        let date = result.data.last_read_date;
                                        console.log(date, "date")
                                        serverModel.getProcessedUIDs(data.queue_id, date).then((processedUIDs) => {
                                            console.log(processedUIDs, "processedUIDs")
                                            if (processedUIDs.status == true) {

                                                const processedUIDsSet = new Set(processedUIDs.data.map(item => item.uid));
                                                imapConnection.search([['SINCE', date]], (err, results) => {
                                                    if (err) {
                                                        callback(`Error searching mailbox: ${err}`, null);
                                                        imapConnection.end();
                                                        return;
                                                    }

                                                    if (results.length === 0) {
                                                        callback("No Mail found", null);
                                                        imapConnection.end();
                                                        return;
                                                    }
                                                    // Filter out the processed UIDs from the results
                                                    const newResults = results.filter(uid => !processedUIDsSet.has(uid));
                                                    if (newResults.length === 0) {
                                                        callback("No new Mail found", null);
                                                        imapConnection.end();
                                                        return;
                                                    }

                                                    // const limitedResults = newResults.slice(0, 50);
                                                    // Fetch the last email's conversation date
                                                    const lastEmailUID = newResults[newResults.length - 1]; // The last email UID
                                                    const fetchOptions = { bodies: ['HEADER.FIELDS (DATE)'], struct: true };
                                                    const fetchRequest = imapConnection.fetch(lastEmailUID, fetchOptions);

                                                    // const limitedResults = results.slice(0, 50);
                                                    // limitedResults.forEach((uid) => {
                                                    //     const fetchOptions = {
                                                    //         bodies: "",
                                                    //         struct: true,
                                                    //         markSeen: true,
                                                    //     };

                                                    // const fetchRequest = imapConnection.fetch(uid, fetchOptions);

                                                    fetchRequest.on("message", (msg) => {
                                                        Log.incErrorLog(`reading mail of ${data.incoming_user_name}`);
                                                        msg.on("body", (stream, info) => {
                                                            let buffer = "";
                                                            stream.on("data", (chunk) => (buffer += chunk));
                                                            stream.on("end", () => {
                                                                const lastEmailDate = this.getEmailDateFromBuffer(buffer, data, lastEmailUID); // Only get the date
                                                                if (lastEmailDate.startsWith("Error")) {
                                                                    callback(emailDate, null); // If error message, pass it to the callback
                                                                    imapConnection.end();
                                                                }
                                                                serverModel.updateLastReadDate(data.queue_id, lastEmailDate).then((result) => {
                                                                    if (result.status) {
                                                                        Log.incErrorLog(`last unread mail date updated for mail id  ${data.incoming_user_name} ,${lastEmailDate}`);
                                                                    }
                                                                })
                                                                const emailPromises = newResults.map(async (uid) => {
                                                                    Log.incErrorLog(`Processing uid ${uid}`)
                                                                    const fetchOptions = { bodies: '', struct: true, markSeen: true };
                                                                    const fetchRequest = imapConnection.fetch(uid, fetchOptions);
                                                                    fetchRequest.on('message', msg => {
                                                                        Log.incErrorLog(`Reading mail of ${data.incoming_user_name}`);
                                                                        let buffer = '';

                                                                        msg.on('body', (stream) => {
                                                                            stream.on('data', chunk => buffer += chunk);
                                                                            // stream.on('end', () => this.processParsedEmail(buffer, data, callback));
                                                                            stream.on('end', () => {
                                                                                simpleParser(buffer, (err, parsed) => {
                                                                                    if (err) {
                                                                                        Log.incErrorLog({ error: err });
                                                                                        return;
                                                                                    } else {
                                                                                        Log.incErrorLog(`reading mail data`);
                                                                                        var headerData = Object.fromEntries(parsed.headers);
                                                                                        console.log("headerData", headerData);

                                                                                        Log.incErrorLog(
                                                                                            ` mail received from ${JSON.stringify(
                                                                                                headerData.from.value
                                                                                            )}`
                                                                                        );

                                                                                        if (this.shouldBlockEmail(data, headerData)) {
                                                                                            Log.incErrorLog(
                                                                                                "Blocking email for ticket generation"
                                                                                            );
                                                                                            return;
                                                                                        }

                                                                                        if (this.shouldBlockDomain(data, headerData)) {
                                                                                            Log.incErrorLog(
                                                                                                "Blocking domain for ticket generation"
                                                                                            );
                                                                                            return;
                                                                                        }

                                                                                        // if (!this.isRecipientFound(data, headerData)) {
                                                                                        //   Log.incErrorLog('Recipient email not found in queue');
                                                                                        //   return;
                                                                                        // }

                                                                                        if (
                                                                                            this.isSameEmail(
                                                                                                data.incoming_user_name,
                                                                                                headerData.from.value[0].address
                                                                                            )
                                                                                        ) {
                                                                                            Log.incErrorLog(
                                                                                                "Sender and recipient email addresses cannot be the same"
                                                                                            );
                                                                                            return;
                                                                                        }
                                                                                        headerData.date = this.dateFormat(headerData.date);
                                                                                        // console.log("formattedDate",formattedDate)
                                                                                        // console.log("headerData.date",headerData.date)
                                                                                        var encmessageId = headerData["message-id"];
                                                                                        // var charmessageId = encmessageId.replace(
                                                                                        //   /[<>\-.]/g,
                                                                                        //   ""
                                                                                        // );
                                                                                        var charmessageId = encmessageId.replace(
                                                                                            /[<>.\-\/]/g,
                                                                                            ""
                                                                                        );
                                                                                        var msgId = charmessageId.split("@")[0];
                                                                                        console.log(" data.queue_id", data.queue_id)
                                                                                        serverModel.checkMessageIdInDb(headerData['message-id'], data.queue_id)
                                                                                            .then((result) => {
                                                                                                Log.incErrorLog(`messageId is ${headerData['message-id']}`);
                                                                                                Log.incErrorLog(`result is ${JSON.stringify(result)}`);

                                                                                                const isDataNonEmptyObject = result.status &&
                                                                                                    result.data &&
                                                                                                    typeof result.data === 'object' &&
                                                                                                    Object.keys(result.data).length > 0;

                                                                                                // Log.incErrorLog(`isDataNonEmptyObject is ${isDataNonEmptyObject}`);
                                                                                                console.log(isDataNonEmptyObject, "isDataNonEmptyObject")
                                                                                                // Log.incErrorLog(`result.data is ${JSON.stringify(result.data)}`);

                                                                                                if (isDataNonEmptyObject) {
                                                                                                    Log.incErrorLog(`uid ${uid} exists in the database or headerData is an empty object. Ticket will not be generated.`);
                                                                                                    Log.incErrorLog(`Message with ID ${headerData['message-id']} already exists in the database or headerData is empty. Skipping ticket generation.`);
                                                                                                    return;
                                                                                                }
                                                                                            })
                                                                                            .catch((error) => {
                                                                                                Log.errorLog({ error });
                                                                                                Log.incErrorLog(`Error checking message ID in database: ${error.message}`);
                                                                                            });

                                                                                        // var bodyData = parsed.text
                                                                                        // var bodyData = parsed.textAsHtml
                                                                                        // var bodyData = parsed.html
                                                                                        if (parsed.html == false) {
                                                                                            var bodyData = parsed.textAsHtml;
                                                                                        } else {
                                                                                            var bodyData = parsed.html;
                                                                                        }
                                                                                        var attachmentData = [];
                                                                                        for (const attachment of parsed.attachments) {
                                                                                            if (attachment.filename != undefined) {
                                                                                                Log.incErrorLog({
                                                                                                    msg: ` filename ${attachment.filename}`,
                                                                                                });
                                                                                                const attachmentContent = Buffer.from(
                                                                                                    attachment.content.toString("binary"),
                                                                                                    "binary"
                                                                                                );
                                                                                                const attachmentFileName = attachment.filename;
                                                                                                attachmentData.push({
                                                                                                    filename: attachment.filename,
                                                                                                    contentType: attachment.contentType,
                                                                                                    attachmentContent:
                                                                                                        attachmentContent.toString("base64"),
                                                                                                });
                                                                                                if (attachmentData.length > 0) {
                                                                                                    var mainfolderpath = path.join(
                                                                                                        __dirname,
                                                                                                        "mail_json_file"
                                                                                                    );
                                                                                                    const folderName = msgId;
                                                                                                    const today = new Date();
                                                                                                    const todayISOString = new Date(today.getTime() - (today.getTimezoneOffset() * 60000)).toISOString().slice(0, 10);
                                                                                                    const todayFolderPath = path.join(
                                                                                                        mainfolderpath,
                                                                                                        todayISOString
                                                                                                    );
                                                                                                    const folderPath = path.join(
                                                                                                        todayFolderPath,
                                                                                                        folderName
                                                                                                    );

                                                                                                    try {
                                                                                                        if (!fs.existsSync(todayFolderPath)) {
                                                                                                            fs.mkdirSync(todayFolderPath);
                                                                                                            fs.chmodSync(todayFolderPath, 0o777);
                                                                                                            Log.incErrorLog(
                                                                                                                `Folder created for attachment: ${todayFolderPath}`
                                                                                                            );
                                                                                                        }

                                                                                                        if (!fs.existsSync(folderPath)) {
                                                                                                            fs.mkdirSync(folderPath);
                                                                                                            fs.chmodSync(folderPath, 0o777);
                                                                                                            Log.incErrorLog(
                                                                                                                `Folder created for attachment: ${folderPath}`
                                                                                                            );
                                                                                                        }

                                                                                                        const attachmentFilePath = path.join(
                                                                                                            folderPath,
                                                                                                            attachmentFileName
                                                                                                        );

                                                                                                        fs.writeFile(
                                                                                                            attachmentFilePath,
                                                                                                            attachmentContent,
                                                                                                            (err) => {
                                                                                                                if (err) {
                                                                                                                    Log.incErrorLog(
                                                                                                                        `Error saving attachment ${attachmentFileName}: ${err}`
                                                                                                                    );
                                                                                                                    return callback(err, null);
                                                                                                                } else {
                                                                                                                    Log.incErrorLog(
                                                                                                                        `Attachment ${attachmentFileName} saved successfully.`
                                                                                                                    );
                                                                                                                }
                                                                                                            }
                                                                                                        );
                                                                                                    } catch (err) {
                                                                                                        Log.incErrorLog(
                                                                                                            `Error creating folders or writing attachment: ${err}`
                                                                                                        );
                                                                                                        return callback(err, null);
                                                                                                    }
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                    let base64ENCdata =
                                                                                        Buffer.from(bodyData).toString("base64");
                                                                                    var finalData = JSON.stringify({
                                                                                        headerData,
                                                                                        bodyData: base64ENCdata,
                                                                                        attachmentData,
                                                                                        uid: uid
                                                                                    });

                                                                                    const fileName = `${msgId}.json`;

                                                                                    var mainfolderpath = path.join(
                                                                                        __dirname,
                                                                                        "mail_json_file"
                                                                                    );
                                                                                    const folderName = msgId;
                                                                                    const today = new Date();
                                                                                    console.log("today", today)
                                                                                    const todayISOString = new Date(today.getTime() - (today.getTimezoneOffset() * 60000)).toISOString().slice(0, 10);
                                                                                    console.log("todayISOString", todayISOString)

                                                                                    const todayFolderPath = path.join(
                                                                                        mainfolderpath,
                                                                                        todayISOString
                                                                                    );
                                                                                    const folderPath = path.join(
                                                                                        todayFolderPath,
                                                                                        folderName
                                                                                    );

                                                                                    try {
                                                                                        if (!fs.existsSync(todayFolderPath)) {
                                                                                            fs.mkdirSync(todayFolderPath);
                                                                                            fs.chmodSync(todayFolderPath, 0o777);
                                                                                        } else {
                                                                                            Log.incErrorLog(
                                                                                                `Folder already exists for json file: ${todayFolderPath}`
                                                                                            );
                                                                                        }
                                                                                        if (!fs.existsSync(folderPath)) {
                                                                                            fs.mkdirSync(folderPath);
                                                                                            fs.chmodSync(folderPath, 0o777);
                                                                                        } else {
                                                                                            Log.incErrorLog(
                                                                                                `Folder already exists for json file: ${folderPath}`
                                                                                            );
                                                                                        }
                                                                                        const finalpath = path.join(folderPath, fileName);

                                                                                        fs.writeFile(finalpath, finalData, (writeErr) => {
                                                                                            if (writeErr) {
                                                                                                Log.incErrorLog({ error: writeErr });
                                                                                                return callback(writeErr, null);
                                                                                            } else {
                                                                                                var fileFolderPath = `${todayISOString}/${folderName}/`;
                                                                                                Log.incErrorLog(
                                                                                                    `Mail data saved to JSON file ${headerData}`
                                                                                                );

                                                                                                if ("references" in headerData) {
                                                                                                    const references = headerData["references"];
                                                                                                    serverModel
                                                                                                        .getReferenceData(references, data.queue_id)
                                                                                                        .then((result) => {
                                                                                                            if (result.status === true) {
                                                                                                                const idDataList = [];
                                                                                                                const idData = result.data;

                                                                                                                if (Object.keys(idData).length > 0) {
                                                                                                                    idDataList.push({
                                                                                                                        ticket_unique_id:
                                                                                                                            idData.ticket_unique_id,
                                                                                                                    });
                                                                                                                }

                                                                                                                if (idDataList.length > 0) {
                                                                                                                    serverModel
                                                                                                                        .getTicketIdRefrenceData(
                                                                                                                            data.queue_id,
                                                                                                                            idDataList[0].ticket_unique_id
                                                                                                                        )
                                                                                                                        .then((result) => {
                                                                                                                            const replyTicketDataList = [];
                                                                                                                            if (result.status === true) {
                                                                                                                                const replyTicketData =
                                                                                                                                    result.data;
                                                                                                                                if (
                                                                                                                                    Object.keys(replyTicketData)
                                                                                                                                        .length > 0
                                                                                                                                ) {
                                                                                                                                    replyTicketDataList.push({
                                                                                                                                        ticket_unique_id:
                                                                                                                                            replyTicketData.ticket_unique_id,
                                                                                                                                        status_id:
                                                                                                                                            replyTicketData.status_id,
                                                                                                                                        conversation_date:
                                                                                                                                            replyTicketData.conversation_date,
                                                                                                                                        conversation_id:
                                                                                                                                            replyTicketData.conversation_id,
                                                                                                                                        assigned_to:
                                                                                                                                            replyTicketData.assigned_to,
                                                                                                                                        is_assigned:
                                                                                                                                            replyTicketData.is_assigned,
                                                                                                                                    });
                                                                                                                                }
                                                                                                                            }

                                                                                                                            const dataWithMsgId = {
                                                                                                                                ...JSON.parse(finalData),
                                                                                                                                msgId,
                                                                                                                                fileFolderPath,
                                                                                                                                replyTicketDataList,
                                                                                                                            };

                                                                                                                            callback(null, dataWithMsgId);
                                                                                                                        });
                                                                                                                } else {
                                                                                                                    if (
                                                                                                                        !this.isRecipientFound(
                                                                                                                            data,
                                                                                                                            headerData
                                                                                                                        )
                                                                                                                    ) {
                                                                                                                        Log.incErrorLog(
                                                                                                                            "Recipient email not found in queue"
                                                                                                                        );
                                                                                                                        return;
                                                                                                                    } else {
                                                                                                                        const dataWithMsgId = {
                                                                                                                            ...JSON.parse(finalData),
                                                                                                                            msgId,
                                                                                                                            fileFolderPath,
                                                                                                                        };
                                                                                                                        callback(null, dataWithMsgId);
                                                                                                                    }
                                                                                                                }
                                                                                                            } else {
                                                                                                                if (
                                                                                                                    !this.isRecipientFound(data, headerData)
                                                                                                                ) {
                                                                                                                    Log.incErrorLog(
                                                                                                                        "Recipient email not found in queue"
                                                                                                                    );
                                                                                                                    return;
                                                                                                                }
                                                                                                            }
                                                                                                        });
                                                                                                } else {
                                                                                                    if (!this.isRecipientFound(data, headerData)) {
                                                                                                        Log.incErrorLog(
                                                                                                            "Recipient email not found in queue"
                                                                                                        );
                                                                                                        return;
                                                                                                    }
                                                                                                    const dataWithMsgId = {
                                                                                                        ...JSON.parse(finalData),
                                                                                                        msgId,
                                                                                                        fileFolderPath,
                                                                                                    };
                                                                                                    callback(null, dataWithMsgId);
                                                                                                }
                                                                                            }
                                                                                        });
                                                                                    } catch (err) {
                                                                                        Log.incErrorLog(
                                                                                            `Error creating folders or writing JSON file: ${err}`
                                                                                        );
                                                                                        callback(err, null);
                                                                                    }
                                                                                });
                                                                                imapConnection.addFlags(uid, '\\Seen', (err) => {
                                                                                    if (err) {
                                                                                        Log.incErrorLog(`Failed to mark message as seen for ${data.incoming_user_name}: ${err}`);
                                                                                    } else {
                                                                                        Log.incErrorLog(`Message marked as seen for ${data.incoming_user_name}`);
                                                                                    }
                                                                                });
                                                                            })
                                                                        })
                                                                    })


                                                                });
                                                            });
                                                        });
                                                    });

                                                    fetchRequest.once("error", (err) => {
                                                        callback(`Error processing message: ${err}`, null);
                                                    });

                                                    fetchRequest.once("end", () => {
                                                        Log.incErrorLog("Finished processing message");
                                                    });
                                                    // });


                                                })

                                            }



                                        })

                                    }



                                })

                            } else {
                                Log.incErrorLog(`No messages found for ${data.incoming_user_name}`);
                                imapConnection.search(
                                    ["UNSEEN", ["SINCE", `${dateString}`]],
                                    (err, results) => {
                                        if (err) {
                                            callback(`Error searching for emails: ${err}`, null);
                                        }

                                        if (results.length === 0) {
                                            callback("No Mail found", null);
                                        }
                                        const limitedResults = results.slice(0, 50);
                                        limitedResults.forEach((uid) => {
                                            const fetchOptions = {
                                                bodies: "",
                                                struct: true,
                                                markSeen: true,
                                            };

                                            const fetchRequest = imapConnection.fetch(uid, fetchOptions);

                                            fetchRequest.on("message", (msg) => {
                                                Log.incErrorLog(`reading mail of ${data.incoming_user_name}`);
                                                msg.on("body", (stream, info) => {
                                                    let buffer = "";
                                                    stream.on("data", (chunk) => (buffer += chunk));
                                                    stream.on("end", () => {
                                                        simpleParser(buffer, (err, parsed) => {
                                                            if (err) {
                                                                Log.incErrorLog({ error: err });
                                                                return;
                                                            } else {
                                                                Log.incErrorLog(`reading mail data`);
                                                                var headerData = Object.fromEntries(parsed.headers);

                                                                Log.incErrorLog(
                                                                    ` mail received from ${JSON.stringify(
                                                                        headerData.from.value
                                                                    )}`
                                                                );

                                                                if (this.shouldBlockEmail(data, headerData)) {
                                                                    Log.incErrorLog(
                                                                        "Blocking email for ticket generation"
                                                                    );
                                                                    return;
                                                                }

                                                                if (this.shouldBlockDomain(data, headerData)) {
                                                                    Log.incErrorLog(
                                                                        "Blocking domain for ticket generation"
                                                                    );
                                                                    return;
                                                                }

                                                                // if (!this.isRecipientFound(data, headerData)) {
                                                                //   Log.incErrorLog('Recipient email not found in queue');
                                                                //   return;
                                                                // }

                                                                if (
                                                                    this.isSameEmail(
                                                                        data.incoming_user_name,
                                                                        headerData.from.value[0].address
                                                                    )
                                                                ) {
                                                                    Log.incErrorLog(
                                                                        "Sender and recipient email addresses cannot be the same"
                                                                    );
                                                                    return;
                                                                }
                                                                headerData.date = this.dateFormat(headerData.date);
                                                                // console.log("formattedDate",formattedDate)
                                                                // console.log("headerData.date",headerData.date)
                                                                var encmessageId = headerData["message-id"];
                                                                // var charmessageId = encmessageId.replace(
                                                                //   /[<>\-.]/g,
                                                                //   ""
                                                                // );
                                                                var charmessageId = encmessageId.replace(
                                                                    /[<>.\-\/]/g,
                                                                    ""
                                                                );
                                                                var msgId = charmessageId.split("@")[0];
                                                                // var bodyData = parsed.text
                                                                // var bodyData = parsed.textAsHtml
                                                                // var bodyData = parsed.html
                                                                if (parsed.html == false) {
                                                                    var bodyData = parsed.textAsHtml;
                                                                } else {
                                                                    var bodyData = parsed.html;
                                                                }
                                                                var attachmentData = [];
                                                                for (const attachment of parsed.attachments) {
                                                                    if (attachment.filename != undefined) {
                                                                        Log.incErrorLog({
                                                                            msg: ` filename ${attachment.filename}`,
                                                                        });
                                                                        const attachmentContent = Buffer.from(
                                                                            attachment.content.toString("binary"),
                                                                            "binary"
                                                                        );
                                                                        const attachmentFileName = attachment.filename;
                                                                        attachmentData.push({
                                                                            filename: attachment.filename,
                                                                            contentType: attachment.contentType,
                                                                            attachmentContent:
                                                                                attachmentContent.toString("base64"),
                                                                        });
                                                                        if (attachmentData.length > 0) {
                                                                            var mainfolderpath = path.join(
                                                                                __dirname,
                                                                                "mail_json_file"
                                                                            );
                                                                            const folderName = msgId;
                                                                            const today = new Date();
                                                                            const todayISOString = new Date(today.getTime() - (today.getTimezoneOffset() * 60000)).toISOString().slice(0, 10);
                                                                            const todayFolderPath = path.join(
                                                                                mainfolderpath,
                                                                                todayISOString
                                                                            );
                                                                            const folderPath = path.join(
                                                                                todayFolderPath,
                                                                                folderName
                                                                            );

                                                                            try {
                                                                                if (!fs.existsSync(todayFolderPath)) {
                                                                                    fs.mkdirSync(todayFolderPath);
                                                                                    fs.chmodSync(todayFolderPath, 0o777);
                                                                                    Log.incErrorLog(
                                                                                        `Folder created for attachment: ${todayFolderPath}`
                                                                                    );
                                                                                }

                                                                                if (!fs.existsSync(folderPath)) {
                                                                                    fs.mkdirSync(folderPath);
                                                                                    fs.chmodSync(folderPath, 0o777);
                                                                                    Log.incErrorLog(
                                                                                        `Folder created for attachment: ${folderPath}`
                                                                                    );
                                                                                }

                                                                                const attachmentFilePath = path.join(
                                                                                    folderPath,
                                                                                    attachmentFileName
                                                                                );

                                                                                fs.writeFile(
                                                                                    attachmentFilePath,
                                                                                    attachmentContent,
                                                                                    (err) => {
                                                                                        if (err) {
                                                                                            Log.incErrorLog(
                                                                                                `Error saving attachment ${attachmentFileName}: ${err}`
                                                                                            );
                                                                                            return callback(err, null);
                                                                                        } else {
                                                                                            Log.incErrorLog(
                                                                                                `Attachment ${attachmentFileName} saved successfully.`
                                                                                            );
                                                                                        }
                                                                                    }
                                                                                );
                                                                            } catch (err) {
                                                                                Log.incErrorLog(
                                                                                    `Error creating folders or writing attachment: ${err}`
                                                                                );
                                                                                return callback(err, null);
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                            let base64ENCdata =
                                                                Buffer.from(bodyData).toString("base64");
                                                            var finalData = JSON.stringify({
                                                                headerData,
                                                                bodyData: base64ENCdata,
                                                                attachmentData,
                                                            });

                                                            const fileName = `${msgId}.json`;

                                                            var mainfolderpath = path.join(
                                                                __dirname,
                                                                "mail_json_file"
                                                            );
                                                            const folderName = msgId;
                                                            const today = new Date();
                                                            console.log("today", today)
                                                            const todayISOString = new Date(today.getTime() - (today.getTimezoneOffset() * 60000)).toISOString().slice(0, 10);
                                                            console.log("todayISOString", todayISOString)

                                                            const todayFolderPath = path.join(
                                                                mainfolderpath,
                                                                todayISOString
                                                            );
                                                            const folderPath = path.join(
                                                                todayFolderPath,
                                                                folderName
                                                            );

                                                            try {
                                                                if (!fs.existsSync(todayFolderPath)) {
                                                                    fs.mkdirSync(todayFolderPath);
                                                                    fs.chmodSync(todayFolderPath, 0o777);
                                                                } else {
                                                                    Log.incErrorLog(
                                                                        `Folder already exists for json file: ${todayFolderPath}`
                                                                    );
                                                                }
                                                                if (!fs.existsSync(folderPath)) {
                                                                    fs.mkdirSync(folderPath);
                                                                    fs.chmodSync(folderPath, 0o777);
                                                                } else {
                                                                    Log.incErrorLog(
                                                                        `Folder already exists for json file: ${folderPath}`
                                                                    );
                                                                }
                                                                const finalpath = path.join(folderPath, fileName);

                                                                fs.writeFile(finalpath, finalData, (writeErr) => {
                                                                    if (writeErr) {
                                                                        Log.incErrorLog({ error: writeErr });
                                                                        return callback(writeErr, null);
                                                                    } else {

                                                                        var fileFolderPath = `${todayISOString}/${folderName}/`;

                                                                        Log.incErrorLog(
                                                                            `Mail data saved to JSON file ${headerData}`
                                                                        );

                                                                        if ("references" in headerData) {
                                                                            const references = headerData["references"];
                                                                            serverModel
                                                                                .getReferenceData(references, data.queue_id)
                                                                                .then((result) => {
                                                                                    if (result.status === true) {
                                                                                        const idDataList = [];
                                                                                        const idData = result.data;

                                                                                        if (Object.keys(idData).length > 0) {
                                                                                            idDataList.push({
                                                                                                ticket_unique_id:
                                                                                                    idData.ticket_unique_id,
                                                                                            });
                                                                                        }

                                                                                        if (idDataList.length > 0) {
                                                                                            serverModel
                                                                                                .getTicketIdRefrenceData(
                                                                                                    data.queue_id,
                                                                                                    idDataList[0].ticket_unique_id
                                                                                                )
                                                                                                .then((result) => {
                                                                                                    const replyTicketDataList = [];
                                                                                                    if (result.status === true) {
                                                                                                        const replyTicketData =
                                                                                                            result.data;
                                                                                                        if (
                                                                                                            Object.keys(replyTicketData)
                                                                                                                .length > 0
                                                                                                        ) {
                                                                                                            replyTicketDataList.push({
                                                                                                                ticket_unique_id:
                                                                                                                    replyTicketData.ticket_unique_id,
                                                                                                                status_id:
                                                                                                                    replyTicketData.status_id,
                                                                                                                conversation_date:
                                                                                                                    replyTicketData.conversation_date,
                                                                                                                conversation_id:
                                                                                                                    replyTicketData.conversation_id,
                                                                                                                assigned_to:
                                                                                                                    replyTicketData.assigned_to,
                                                                                                                is_assigned:
                                                                                                                    replyTicketData.is_assigned,
                                                                                                            });
                                                                                                        }
                                                                                                    }

                                                                                                    const dataWithMsgId = {
                                                                                                        ...JSON.parse(finalData),
                                                                                                        msgId,
                                                                                                        fileFolderPath,
                                                                                                        replyTicketDataList,
                                                                                                    };

                                                                                                    callback(null, dataWithMsgId);
                                                                                                });
                                                                                        } else {
                                                                                            if (
                                                                                                !this.isRecipientFound(
                                                                                                    data,
                                                                                                    headerData
                                                                                                )
                                                                                            ) {
                                                                                                Log.incErrorLog(
                                                                                                    "Recipient email not found in queue"
                                                                                                );
                                                                                                return;
                                                                                            } else {
                                                                                                const dataWithMsgId = {
                                                                                                    ...JSON.parse(finalData),
                                                                                                    msgId,
                                                                                                    fileFolderPath,
                                                                                                };
                                                                                                callback(null, dataWithMsgId);
                                                                                            }
                                                                                        }
                                                                                    } else {
                                                                                        if (
                                                                                            !this.isRecipientFound(data, headerData)
                                                                                        ) {
                                                                                            Log.incErrorLog(
                                                                                                "Recipient email not found in queue"
                                                                                            );
                                                                                            return;
                                                                                        }
                                                                                    }
                                                                                });
                                                                        } else {
                                                                            if (!this.isRecipientFound(data, headerData)) {
                                                                                Log.incErrorLog(
                                                                                    "Recipient email not found in queue"
                                                                                );
                                                                                return;
                                                                            }
                                                                            const dataWithMsgId = {
                                                                                ...JSON.parse(finalData),
                                                                                msgId,
                                                                                fileFolderPath,
                                                                            };
                                                                            callback(null, dataWithMsgId);
                                                                        }
                                                                    }
                                                                });
                                                            } catch (err) {
                                                                Log.incErrorLog(
                                                                    `Error creating folders or writing JSON file: ${err}`
                                                                );
                                                                callback(err, null);
                                                            }
                                                        });
                                                    });
                                                });
                                            });

                                            fetchRequest.once("error", (err) => {
                                                callback(`Error processing message: ${err}`, null);
                                            });

                                            fetchRequest.once("end", () => {
                                                Log.incErrorLog("Finished processing message");
                                            });
                                        });
                                    }
                                );
                            }
                        });
                    });

                    imapConnection.once("error", async (err) => {
                        Log.incErrorLog(`IMAP connection error: ${err} for ${data.incoming_user_name}`);

                        if (data.is_auth_enable === 1) {
                            try {
                                Log.incErrorLog('function calling time : ' + new Date().toLocaleString());
                                await this.refreshAuthToken(data.refresh_token, data.client_secret, data.client_oauth2_id, data.tenant_id, data.incoming_user_name, data.compToken);
                                imapConnection.end();
                            } catch (refreshError) {
                                callback(`Failed to refresh token for ${data.incoming_user_name}: ${refreshError}`, null);
                            }
                        } else {
                            callback(
                                `IMAP connection error: ${err} ${data.incoming_user_name}`,
                                null
                            );
                        }
                    });



                    imapConnection.once("end", () => {
                        Log.incErrorLog("IMAP connection closed");
                    });
                    imapConnection.connect();
                });
            };
            // Retry Loop
            while (retries < MAX_RETRIES) {
                try {
                    await tryConnect();
                    return; // success
                } catch (err) {
                    retries++;
                    if (err === 'EBUSY') {
                        Log.incErrorLog(`Retrying IMAP (${incoming_user_name}) due to DNS EBUSY... Attempt ${retries}`);
                        await new Promise(res => setTimeout(res, RETRY_DELAY_MS));
                        continue;
                    } else {
                        return callback(`Error on IMAP connect for ${incoming_user_name}: ${err}`, null);
                    }
                }
            }
        } catch (err) {
            callback(`Unexpected error: ${err} ${data.incoming_user_name}`, null);
        }
    }



    // async refreshAuthToken(rf_token, client_secret, client_oauth2_id, tenant_id, incoming_user_name, compToken) {
    //     try {

    //         const url = `https://login.microsoftonline.com/${tenant_id}/oauth2/v2.0/token`;

    //         const data = qs.stringify({
    //             grant_type: 'refresh_token',
    //             client_id: client_oauth2_id,
    //             client_secret: client_secret,
    //             refresh_token: rf_token,
    //             // scope: 'https://outlook.office365.com/IMAP.AccessAsUser.All offline_access'
    //             scope: 'https://outlook.office365.com/.default'
    //         });
    //         Log.incErrorLog("Data for token refresh: " + JSON.stringify(data));

    //         const response = await axios.post(url, data, {
    //             headers: {
    //                 'Content-Type': 'application/x-www-form-urlencoded',
    //             }
    //         });
    //         Log.incErrorLog(`Token refreshed successfully for ${incoming_user_name}`);
    //         Log.incErrorLog(`Response data: ${JSON.stringify(response.data)}`);
    //         const { refresh_token, access_token } = response.data;
    //         serverModel.saveToken(refresh_token, access_token, incoming_user_name).then(async (result) => {
    //             if (result.status == true) {
    //                 try {
    //                     await emailOperation.handlerTokenCompanyObj();
    //                     Log.incErrorLog(`handlerUpdateCompanyObj function executed successfully`);
    //                 } catch (funcError) {
    //                     Log.incErrorLog(`Error executing handlerUpdateCompanyObj: ${funcError.message}`);
    //                 }
    //                 Log.incErrorLog(`Token updated successfully`);
    //             } else {
    //                 Log.incErrorLog(`Error while updating token`);
    //                 throw new Error('Failed to refresh token');
    //             }
    //         })

    //     } catch (error) {
    //         Log.incErrorLog(`Failed to refresh token: ${error.message}`);
    //         throw new Error('Failed to refresh token');
    //     }
    // }

    async refreshAuthToken(rf_token, client_secret, client_oauth2_id, tenant_id, incoming_user_name, compToken) {
        try {

            const url = `https://login.microsoftonline.com/${tenant_id}/oauth2/v2.0/token`;

            const data = qs.stringify({
                grant_type: 'refresh_token',
                client_id: client_oauth2_id,
                client_secret: client_secret,
                refresh_token: rf_token,
                // scope: 'https://outlook.office365.com/IMAP.AccessAsUser.All offline_access'
                scope: 'https://outlook.office365.com/.default'
            });
            Log.incErrorLog("Data for token refresh: " + JSON.stringify(data));
            Log.incErrorLog('Data for token time : ' + new Date().toLocaleString());
            const response = await axios.post(url, data, {
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded',
                }
            });
            // Log.incErrorLog(`Token refreshed successfully for ${incoming_user_name}`);
            // Log.incErrorLog(`Response data: ${JSON.stringify(response)}`);
            const { refresh_token, access_token } = response.data;
            serverModel.saveToken(refresh_token, access_token, incoming_user_name).then(async (result) => {
                if (result.status == true) {
                    try {
                        await emailOperation.handlerTokenCompanyObj();
                        Log.incErrorLog(`handlerUpdateCompanyObj function executed successfully`);
                    } catch (funcError) {
                        Log.incErrorLog(`Error executing handlerUpdateCompanyObj: ${funcError.message}`);
                    }
                    Log.incErrorLog(`Token updated successfully`);
                } else {
                    Log.incErrorLog(`Error while updating token`);
                    throw new Error('Failed to refresh token');
                }
            })

        } catch (error) {
            Log.incErrorLog(`Failed to refresh token: ${error.message}`);
            throw new Error('Failed to refresh token');
        }
    }


    shouldBlockEmail(data, headerData) {
        const blockEmailsIds = data.block_email_for_ticket_generate.split(",");
        const BlocKEmailFlag = headerData.from.value.some((entry) =>
            blockEmailsIds.includes(entry.address)
        );
        Log.incErrorLog(` BlocKEmailFlag ${BlocKEmailFlag}`);
        return BlocKEmailFlag;
    }

    shouldBlockDomain(data, headerData) {
        const blockDomains = data.block_domains_for_ticket_generate.split(",");
        return headerData.from.value.some((entry) => {
            const domain = entry.address.split("@")[1];
            return blockDomains.includes(domain);
        });
    }

    isRecipientFound(data, headerData) {
        if (data.forwarded_mail === "" || data.forwarded_mail === null) {
            return headerData.to.value.some(
                (entry) => entry.address === data.incoming_user_name
            );
        } else {
            return headerData.to.value.some(
                (entry) => entry.address === data.forwarded_mail || entry.address === data.incoming_user_name
            );
        }
    }

    isSameEmail(senderEmail, recipientEmail) {
        return senderEmail === recipientEmail;
    }

    dateFormat(dateVal) {
        const dateObj = new Date(dateVal);
        const year = dateObj.getFullYear();
        const month = String(dateObj.getMonth() + 1).padStart(2, "0");
        const date = String(dateObj.getDate()).padStart(2, "0");
        const hour = String(dateObj.getHours()).padStart(2, "0");
        const minute = String(dateObj.getMinutes()).padStart(2, "0");
        const second = String(dateObj.getSeconds()).padStart(2, "0");

        return `${year}-${month}-${date} ${hour}:${minute}:${second}`;
    }
    getEmailDateFromBuffer(buffer, data, uid) {
        const dateMatch = buffer.match(/Date:\s*(.*?)(\r?\n|$)/);

        if (dateMatch && dateMatch[1]) {
            const emailDate = dateMatch[1].trim();
            console.log("Extracted raw email date:", emailDate);

            const date = new Date(emailDate);

            if (isNaN(date)) {
                return "Error: Invalid email date format";
            }

            const formattedDate = date.toISOString().split('T')[0];
            return formattedDate;
        } else {
            console.error("Failed to extract email date from buffer.");
            return "Error: Unable to fetch email date";
        }
    }


}


module.exports = new mailOperation();
