const Imap = require('imap');
module.exports = Self => {
    Self.remoteMethod('checkInbox', {
        description: 'Check an email inbox and process it',
        accessType: 'READ',
        returns:
            {
                arg: 'body',
                type: 'file',
                root: true
            },
        http: {
            path: `/checkInbox`,
            verb: 'POST'
        }
    });

    Self.checkInbox = async() => {
        let imapConfig = await Self.app.models.WorkerTimeControlParams.findOne();
        let imap = new Imap({
            user: imapConfig.mailUser,
            password: imapConfig.mailPass,
            host: imapConfig.mailHost,
            port: 993,
            tls: true
        });
        let isEmailOk;
        let uid;
        let emailBody;

        function openInbox(cb) {
            imap.openBox('INBOX', true, cb);
        }

        imap.once('ready', function() {
            openInbox(function(err, box) {
                if (err) throw err;
                const totalMessages = box.messages.total;
                if (totalMessages == 0)
                    imap.end();

                let f = imap.seq.fetch('1:*', {
                    bodies: ['HEADER.FIELDS (FROM SUBJECT)', '1'],
                    struct: true
                });
                f.on('message', function(msg, seqno) {
                    isEmailOk = false;
                    msg.on('body', function(stream, info) {
                        let buffer = '';
                        let bufferCopy = '';
                        stream.on('data', function(chunk) {
                            buffer = chunk.toString('utf8');
                            if (info.which === '1' && bufferCopy.length == 0)
                                bufferCopy = buffer.replace(/\s/g, ' ');
                        });
                        stream.on('end', function() {
                            if (bufferCopy.length > 0) {
                                emailBody = bufferCopy.toUpperCase().trim();

                                const bodyPositionOK = emailBody.match(/\bOK\b/i);
                                if (bodyPositionOK != null && (bodyPositionOK.index == 0 || bodyPositionOK.index == 122))
                                    isEmailOk = true;
                                else
                                    isEmailOk = false;
                            }
                        });
                        msg.once('attributes', function(attrs) {
                            uid = attrs.uid;
                        });
                        msg.once('end', function() {
                            if (info.which === 'HEADER.FIELDS (FROM SUBJECT)') {
                                if (isEmailOk) {
                                    imap.move(uid, 'exito', function(err) {
                                    });
                                    emailConfirm(buffer);
                                } else {
                                    imap.move(uid, 'error', function(err) {
                                    });
                                    emailReply(buffer, emailBody);
                                }
                            }
                        });
                    });
                });
                f.once('end', function() {
                    imap.end();
                });
            });
        });

        imap.connect();
        return 'Leer emails de gestion horaria';
    };

    async function emailConfirm(buffer) {
        const now = Date.vnNew();
        const from = JSON.stringify(Imap.parseHeader(buffer).from);
        const subject = JSON.stringify(Imap.parseHeader(buffer).subject);

        const timeControlDate = await getEmailDate(subject);
        const week = timeControlDate[0];
        const year = timeControlDate[1];
        const user = await getUser(from);
        let workerMail;

        if (user.id != null) {
            workerMail = await Self.app.models.WorkerTimeControlMail.findOne({
                where: {
                    week: week,
                    year: year,
                    workerFk: user.id
                }
            });
        }
        if (workerMail != null) {
            await workerMail.updateAttributes({
                updated: now,
                state: 'CONFIRMED'
            });
        }
    }

    async function emailReply(buffer, emailBody) {
        const now = Date.vnNew();
        const from = JSON.stringify(Imap.parseHeader(buffer).from);
        const subject = JSON.stringify(Imap.parseHeader(buffer).subject);

        const timeControlDate = await getEmailDate(subject);
        const week = timeControlDate[0];
        const year = timeControlDate[1];
        const user = await getUser(from);
        let workerMail;

        if (user.id != null) {
            workerMail = await Self.app.models.WorkerTimeControlMail.findOne({
                where: {
                    week: week,
                    year: year,
                    workerFk: user.id
                }
            });

            if (workerMail != null) {
                await workerMail.updateAttributes({
                    updated: now,
                    state: 'REVISE',
                    reason: emailBody
                });
            } else
                await sendMail(user, subject, emailBody);
        }
    }

    async function getUser(workerEmail) {
        const userEmail = workerEmail.match(/(?<=<)(.*?)(?=>)/);

        let [user] = await Self.rawSql(`SELECT u.id,u.name FROM account.user u
                                            LEFT JOIN account.mailForward m on m.account = u.id
                                            WHERE forwardTo =? OR
                                                CONCAT(u.name,'@verdnatura.es') = ?`,
        [userEmail[0], userEmail[0]]);

        return user;
    }

    async function getEmailDate(subject) {
        const date = subject.match(/\d+/g);
        return date;
    }

    async function sendMail(user, subject, emailBody) {
        const sendTo = 'rrhh@verdnatura.es';
        const emailSubject = subject + ' ' + user.name;

        await Self.app.models.Mail.create({
            receiver: sendTo,
            subject: emailSubject,
            body: emailBody
        });
    }
};