const { getCollection } = require('../utils/collection');
const _ = require('underscore');
const objectql = require('@steedos/objectql');
const { getObject } = objectql;
const { t } = require('@steedos/i18n');
const { map } = require('lodash');

const WebhookQueue = require('../../../src/webhook_queue')

const uuflowManager = {
    getFlow: async function (flow_id, options = {}) {
        if (process.env.STEEDOS_DEBUG) {
            const now = new Date().toISOString();
            console.time('UUFlowManager.getFlow' + now);
        }
        
        const flowsCollection = await getCollection('flows');
        const flow = await flowsCollection.findOne({_id: flow_id}, options);
        
        if (!flow) {
            throw new Error("id有误或此流程已经被删除");
        }
        
        if (process.env.STEEDOS_DEBUG) {
            console.timeEnd('UUFlowManager.getFlow' + now);
        }
        
        return flow;
    },
    getStep: function (instance, flow, step_id) {
        // console.log('getStep: ', instance, flow, step_id)
        const flow_rev = instance.flow_version;
        let isExistStep = null;
        
        if (flow.current._id === flow_rev) {
            isExistStep = _.find(flow.current.steps, (step) => step._id === step_id);
        } else {
            _.each(flow.historys, (history) => {
                if (history._id === flow_rev) {
                    isExistStep = _.find(history.steps, (step) => step._id === step_id);
                    return false; // Break loop
                }
            });
        }
        
        if (!isExistStep) {
            throw new Error("不能获取step");
        }
        
        return isExistStep;
    }
};

const settings = require('@steedos/objectql').getSteedosConfig();


async function count_instance_tasks(query) {
    if(process.env.STEEDOS_WORKFLOW_DISABLE_BADGE === 'true'){
        return 0;
    } 
    return await getObject('instance_tasks').count(query)
}

// 定义全局变量
const pushManager = {};

pushManager.get_to_users = async function (sendFrom, instance, ccUserIds = [], currentUserInfo) {
    let toUsers = [];

    const db = {
        users: await getCollection('users')
    };
  
    const fetchUsersByIds = async (userIds) => {
        return await db.users.find({ _id: { $in: userIds } }).toArray();
    };

    try {
        if (['first_submit_applicant'].includes(sendFrom)) {
            // 申请人
            if (instance.applicant !== instance.submitter) {
                const applicant = await db.users.findOne({ _id: instance.applicant });
                if(applicant) toUsers.push(applicant);
            }
        } else if (['submit_terminate_approve', 'submit_completed_approve', 'submit_pending_rejected_approve', 'approved_completed_approve', 'rejected_completed_approve'].includes(sendFrom)) {
            // 已审批人
            const removeUsers = [instance.applicant, instance.submitter];
            const approveUserIds = instance.outbox_users.filter(userId => !removeUsers.includes(userId));
            toUsers = await fetchUsersByIds(approveUserIds);
        } else if (['reassign_new_inbox_users', 'submit_pending_rejected_inbox', 'submit_pending_inbox', 'first_submit_inbox', 'return_pending_inbox'].includes(sendFrom)) {
            // 待审批人
            toUsers = await fetchUsersByIds(instance.inbox_users || []);
        } else if (['submit_completed_applicant', 'approved_completed_applicant', 'rejected_completed_applicant', 'monitor_delete_applicant', 'submit_terminate_applicant', 'submit_pending_rejected_applicant', 'submit_pending_rejected_applicant_inbox'].includes(sendFrom)) {
            const applicant = await db.users.findOne({ _id: instance.applicant });
            if(applicant) toUsers.push(applicant);
        } else if (['trace_approve_cc', 'trace_approve_cc_submit'].includes(sendFrom) && ccUserIds.length > 0) {
            toUsers = await fetchUsersByIds(ccUserIds);
        } else if (['auto_submit_pending_inbox'].includes(sendFrom)) {
            toUsers = [currentUserInfo];
        }
    } catch (error) {
        console.error("Error fetching users: ", error);
    }
  
    return toUsers;
};

pushManager.get_body = function (parameters, lang = "zh-CN") {
    const {
        send_from,
        applicant_name,
        instance_name,
        to_username,
        href,
        final_decision,
        description,
        state,
        from_username,
        current_step_name,
        nextApprove_usersname,
        nextStep_type,
        approves_description,
        lastApprove_judge,
        lastApprove_usersname,
        current_user_name,
        currentStep_type
    } = parameters;

    let push_final_decision, email_final_decision, email_description = "";

    if (!final_decision) {
        push_final_decision = t('instance.push.final_decision_nil', {}, lang);
        email_final_decision = t('instance.email.final_decision_nil', {}, lang);
    } else if (final_decision === "approved") {
        push_final_decision = t('instance.push.final_decision_approved', {}, lang);
        email_final_decision = t('instance.email.final_decision_approved', {}, lang);
    } else if (final_decision === "rejected") {
        push_final_decision = t('instance.push.final_decision_rejected', {}, lang);
        email_final_decision = t('instance.email.final_decision_rejected', {}, lang);
        email_description = t('instance.email.body.email_description', { description }, lang);
    }

    const approveTypeDict = {
        'submit': 'input',
        'start': 'input',
        'sign': 'approval',
        'counterSign': 'approval'
    };

    const approveTypeKey = approveTypeDict[nextStep_type] || '';
    const email_approve_type = approveTypeKey ? t(`instance.email.body.${approveTypeKey}`, {}, lang) : null;
    const url_approve_type = approveTypeKey ? t(`instance.email.body.url_${approveTypeKey}`, {}, lang) : null;
    const push_approve_type = approveTypeKey ? t(`instance.push.body.${approveTypeKey}`, {}, lang) : null;

    const decisionJudgeDict = {
        "submitted": 'judge_submitted',
        "approved": 'judge_approved',
    };

    const last_approve_judge = lastApprove_judge && t(`instance.email.body.${decisionJudgeDict[lastApprove_judge]}`, {}, lang);

    // 准备邮件和推送模板
    const templateDict = {
        "first_submit_applicant": { 
            email: "first_submit_applicant", 
            email_alt: "first_submit_applicant_beApproveDescription", 
            push: "first_submit_applicant" 
        },
        "first_submit_inbox": { 
            email: "first_submit_inbox", 
            email_alt: "first_submit_inbox_beApproveDescription", 
            push: "first_submit_inbox" 
        },
        "submit_completed_applicant": { 
            email: "submit_completed_applicant", 
            email_alt: "submit_completed_applicant_beApproveDescription", 
            push: "submit_completed_applicant" 
        },
        "submit_completed_approve": { email: "submit_completed_approve", push: "submit_completed_approve" },
        "submit_pending_rejected_applicant_inbox": { email: "submit_pending_rejected_applicant_inbox", push: "submit_pending_rejected_applicant_inbox" },
        "submit_pending_rejected_applicant": { email: "submit_pending_rejected_applicant", push: "submit_pending_rejected_applicant" },
        "submit_pending_rejected_approve": { email: "submit_pending_rejected_approve", push: "submit_pending_rejected_approve" },
        "submit_pending_rejected_inbox": { email: "submit_pending_rejected_inbox", push: "submit_pending_rejected_inbox" },
        "submit_pending_inbox": { 
            email: "submit_pending_inbox", 
            email_alt: "submit_pending_inbox_beApproveDescription", 
            push: "submit_pending_inbox" 
        },
        "submit_terminate_applicant": { email: "submit_terminate_applicant", push: "submit_terminate_applicant" },
        "submit_terminate_approve": { email: "submit_terminate_approve", push: "submit_terminate_approve" },
        "monitor_delete_applicant": { email: "monitor_delete_applicant", push: "monitor_delete_applicant" },
        "approved_completed_applicant": { 
            email: "approved_completed_applicant", 
            email_alt: "approved_completed_applicant_beApproveDescription", 
            push: "approved_completed_applicant" 
        },
        "approved_completed_approve": { email: "approved_completed_approve", push: "approved_completed_approve" },
        "rejected_completed_applicant": { email: "rejected_completed_applicant", push: "rejected_completed_applicant" },
        "rejected_completed_approve": { email: "rejected_completed_approve", push: "rejected_completed_approve" },
        "reassign_new_inbox_users": { email: "reassign_new_inbox_users", push: "reassign_new_inbox_users" },
        "trace_approve_cc": { email: "trace_approve_cc", push: "trace_approve_cc" },
        "trace_approve_cc_submit": { email: "trace_approve_cc_submit", push: "trace_approve_cc_submit" },
        "auto_submit_pending_inbox": { email: "auto_submit_pending_inbox", push: "auto_submit_pending_inbox" },
        "return_pending_inbox": { email: "return_pending_inbox", push: "return_pending_inbox" }
    };

    const body = {};

    if (templateDict.hasOwnProperty(send_from)) {
        const templates = templateDict[send_from];
        const emailTemplate = approves_description && templates.email_alt ? templates.email_alt : templates.email;
        body["email"] = t(`instance.email.body.${emailTemplate}`, {
            instance_name,
            to_username,
            href,
            applicant_name,
            final_decision: email_final_decision,
            description: email_description,
            approves_description,
            lastApprove_usersname,
            last_approve_judge,
            current_username: current_user_name,
            approve_type: email_approve_type,
            url_approve_type: url_approve_type,
            current_step_name,
            nextApprove_usersname
        }, lang);

        body["push"] = t(`instance.push.body.${templates.push}`, {
            instance_name,
            from_username,
            applicant_name,
            final_decision: push_final_decision,
            description,
            approve_type: push_approve_type,
            current_user_name,
            current_step_name,
            nextApprove_usersname
        }, lang);
    }

    return body;
};

pushManager.get_title = function (parameters, lang = "zh-CN") {
    const {
        send_from,
        instance_name,
        from_username,
        applicant_name,
        current_step_name,
        nextApprove_usersname,
        nextStep_type
    } = parameters;

    let approve_type = null;
    if (['submit', 'start'].includes(nextStep_type)) {
        approve_type = t('instance.email.title.input', {}, lang);
    } else if (['sign', 'counterSign'].includes(nextStep_type)) {
        approve_type = t('instance.email.title.approval', {}, lang);
    }

    const commonParams = {
        from_username,
        instance_name,
        applicant_name,
        approve_type,
        nextApprove_usersname,
        current_step_name
    };

    const title = {};

    const titleTemplates = {
        "first_submit_applicant": { 
            email: "first_submit_applicant", 
            push: "first_submit_applicant" 
        },
        "first_submit_inbox": { 
            email: "first_submit_inbox", 
            push: "first_submit_inbox" 
        },
        "submit_completed_applicant": { 
            email: "submit_completed_applicant", 
            push: "submit_completed_applicant" 
        },
        "submit_completed_approve": { 
            email: "submit_completed_approve", 
            push: "submit_completed_approve" 
        },
        "submit_pending_rejected_applicant_inbox": { 
            email: "submit_pending_rejected_applicant_inbox", 
            push: "submit_pending_rejected_applicant_inbox" 
        },
        "submit_pending_rejected_applicant": { 
            email: "submit_pending_rejected_applicant", 
            push: "submit_pending_rejected_applicant" 
        },
        "submit_pending_rejected_approve": { 
            email: "submit_pending_rejected_approve", 
            push: "submit_pending_rejected_approve" 
        },
        "submit_pending_rejected_inbox": { 
            email: "submit_pending_rejected_inbox", 
            push: "submit_pending_rejected_inbox" 
        },
        "submit_pending_inbox": { 
            email: "submit_pending_inbox", 
            push: "submit_pending_inbox" 
        },
        "submit_terminate_applicant": { 
            email: "submit_terminate_applicant", 
            push: "submit_terminate_applicant" 
        },
        "submit_terminate_approve": { 
            email: "submit_terminate_approve", 
            push: "submit_terminate_approve" 
        },
        "monitor_delete_applicant": { 
            email: "monitor_delete_applicant", 
            push: "monitor_delete_applicant" 
        },
        "approved_completed_applicant": { 
            email: "approved_completed_applicant", 
            push: "approved_completed_applicant" 
        },
        "approved_completed_approve": { 
            email: "approved_completed_approve", 
            push: "approved_completed_approve" 
        },
        "rejected_completed_applicant": { 
            email: "rejected_completed_applicant", 
            push: "rejected_completed_applicant" 
        },
        "rejected_completed_approve": { 
            email: "rejected_completed_approve", 
            push: "rejected_completed_approve" 
        },
        "reassign_new_inbox_users": { 
            email: "reassign_new_inbox_users", 
            push: "reassign_new_inbox_users" 
        },
        "trace_approve_cc": { 
            email: "trace_approve_cc", 
            push: "trace_approve_cc" 
        },
        "trace_approve_cc_submit": { 
            push: "trace_approve_cc_submit" 
        },
        "auto_submit_pending_inbox": { 
            email: "auto_submit_pending_inbox", 
            push: "auto_submit_pending_inbox" 
        },
        "return_pending_inbox": { 
            email: "return_pending_inbox", 
            push: "return_pending_inbox" 
        }
    };

    if (titleTemplates.hasOwnProperty(send_from)) {
        const templates = titleTemplates[send_from];
        if (templates.email) {
            title["email"] = t(`instance.email.title.${templates.email}`, commonParams, lang);
        }
        if (templates.push) {
            title["push"] = t(`instance.push.title.${templates.push}`, commonParams, lang);
        }
    }

    return title;
};

pushManager.getSmsBody = function (parameters, lang = "zh-CN") {
    return t('instance.sms.submit_pending_inbox', parameters, lang);
};

pushManager.get_badge = async function (send_from, user_id) {
    if (!['first_submit_inbox', 'submit_pending_rejected_inbox', 
        'submit_pending_inbox', 'current_user', 'terminate_approval', 
        'reassign_new_inbox_users', 'trace_approve_cc', 'trace_approve_cc_submit', 
        'auto_submit_pending_inbox', 'return_pending_inbox'].includes(send_from)) {
        return null;
    }
    if (!user_id) {
        return null;
    }
    let badge = 0;
    const db = {
        space_users: await getCollection('space_users'),
        categories: await getCollection('categories'),
        steedos_keyvalues: await getCollection('steedos_keyvalues')
    }
    let user_spaces = await db.space_users.find({
        user: user_id,
        user_accepted: true
    }, {
        fields: {space: 1}
    }).toArray();

    for (const user_space of user_spaces) {
        var appCategories, c, categories, ref4, sk, sk_new, spaceId;
        spaceId = user_space.space;

        categories = await db.categories.find({
            space: spaceId,
            app: {
                $ne: null
            }
        }, {
            fields: { app: 1 }
        }).toArray();

        if (categories.length > 0) {
            appCategories = _.groupBy(categories, 'app');
            for (const appName in appCategories) {
                const categorys = appCategories[appName]
                var _set, appKeyValue, appKeyValueNew, categoryBadge, categorysIds, ref4;
                categorysIds = _.pluck(categorys, '_id');
                if (appName) {
                    if (categorysIds.length > 0) {

                        categoryBadge = await count_instance_tasks({
                            filters: [
                                ['handler', '=', user_id],
                                ['is_finished', '=', false],
                                ['space', '=', spaceId],
                                ['category', 'in', categorysIds],
                            ]
                        })

                        appKeyValue = await db.steedos_keyvalues.findOne({
                            user: user_id,
                            space: user_space.space,
                            key: 'badge'
                        }, {
                            fields: {
                                _id: 1,
                                value: 1
                            }
                        });
                        if (appKeyValue) {
                            if (((ref4 = appKeyValue.value) != null ? ref4[appName] : void 0) !== categoryBadge) {
                                _set = {};
                                _set['value.' + appName] = categoryBadge;
                                await getObject('steedos_keyvalues').update(appKeyValue._id, _set)
                                continue;
                            }
                        } else {
                            appKeyValueNew = {};
                            appKeyValueNew.user = user_id;
                            appKeyValueNew.space = user_space.space;
                            appKeyValueNew.key = 'badge';
                            appKeyValueNew.value = {};
                            appKeyValueNew.value[appName] = categoryBadge;
                            await getObject('steedos_keyvalues').insert(appKeyValueNew)
                            continue;
                        }
                    }
                }
            }
        }

        // workflow 记录所有待办数量
        c = await count_instance_tasks({
            filters: [
                ['handler', '=', user_id],
                ['is_finished', '=', false],
                ['space', '=', spaceId],
            ]
        })
        badge += c;
        sk = await db.steedos_keyvalues.findOne({
            user: user_id,
            space: user_space.space,
            key: 'badge'
        }, {
            fields: {
                _id: 1,
                value: 1
            }
        });
        if (sk) {
            if (((ref4 = sk.value) != null ? ref4.workflow : void 0) !== c) {
                await getObject('steedos_keyvalues').update(sk._id, {
                    'value.workflow': c
                })
                continue;
            }
        } else {
            sk_new = {};
            sk_new.user = user_id;
            sk_new.space = user_space.space;
            sk_new.key = 'badge';
            sk_new.value = {
                'workflow': c
            };
            await getObject('steedos_keyvalues').insert(sk_new);
            continue;
        }
    }

    sk_all = await db.steedos_keyvalues.findOne({
        user: user_id,
        space: null,
        key: 'badge'
    }, {
        fields: {
            _id: 1
        }
    });
    if (sk_all) {
        await getObject('steedos_keyvalues').update(sk_all._id, {
            'value.workflow': badge
        });
    } else {
        sk_all_new = {};
        sk_all_new.user = user_id;
        sk_all_new.space = null;
        sk_all_new.key = 'badge';
        sk_all_new.value = {
            'workflow': badge
        };
        await getObject('steedos_keyvalues').insert(sk_all_new)
    }
    return badge;
};

// TODO 调整成B6 action
pushManager.send_email_to_SMTP = async function (subject, content, to_user, reply_user) {
    if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER) {
        return;
    }

    if (!to_user.email || !to_user.email_verified || !to_user.email_notification) {
        return;
    }
    try {
        const fromEmail = `${pushManager.checkMailFromNameLength(reply_user.name)} on ${settings.email.from}`;
        const mailOptions = {
            from: fromEmail,              // 发件人地址
            to: to_user.email,            // 收件人地址
            subject: subject,            // 主题
            html: content
        };
        await broker.call('@builder6/email.send', mailOptions)

    } catch (error) {
        console.error(error.stack);
    }
};

pushManager.checkMailFromNameLength = function (name) {
    if (name.length <= 18) {
        return name;
    } else {
        return name.substr(0, 18) + '...';
    }
};

// TODO 手机推送
pushManager.send_message_by_raix_push = async function (data, lang) {
    if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER || !data["data"]) {
        return;
    }

    const db = {
        users: await getCollection('users')
    }

    try {
        const notification = {
            createdAt: new Date(),
            createdBy: '<SERVER>',
            from: data["pushTopic"],
            title: data["data"]["alertTitle"] || "",
            text: data["data"]["alert"] || ""
        };

        if (data["data"]["space_id"] && data["data"]["instance_id"]) {
            notification.payload = {
                space: data["data"]["space_id"],
                instance: data["data"]["instance_id"],
                host: process.env.ROOT_URL
            };
        }

        if (data["data"]["badge"] > -1) {
            notification.badge = data["data"]["badge"];
        }

        const from = data.data.send_from;

        if(!from){
            return ;
        }
        let notificationDoc = {
            name: notification.text,
            body: t('CustomLabels.approval_workflow', {}, lang),
            related_to: {
                o: "instances",
                ids: [notification.payload?.instance]
            },
            related_name: notification.text,
            from: from,
            space: data?.data?.space_id,
            url: `/api/workflow/instances/redirect/${notification.payload?.instance}`
        };
        const users = await db.users.find({
            steedos_id: {
                $in: data.toUsers
            }
        }, {_id: 1}).toArray()

        const toUsers = map(users, '_id')

        await objectql.getSteedosSchema().broker.call('notifications.add', {
            message: notificationDoc,
            from: from,
            to: toUsers
        })

        await objectql.getSteedosSchema().broker.emit('push.send', {
            message: notificationDoc,
            from: from,
            to: toUsers
        })
        

        // data["toUsers"].forEach(userId => {
        //     const user = db.users.findOne({ steedos_id: userId }, { fields: { _id: 1 } });
        //     if (user) {
        //         notification.query = {
        //             userId: user._id,
        //             appName: data["pushTopic"]
        //         };
        //         Push.send(notification);
        //     }
        // });
    } catch (error) {
        console.error(error.stack);
    }
};

//steedos_ids 必须为数组 ； body 如果有，则必须为Hash
pushManager.send_message = function (steedos_ids, body, current_user_info, lang) {
    if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER) {
        return;
    }

    // 检查 steedos_ids 是否是有效的数组，且 body 如果存在必须是对象
    if (!Array.isArray(steedos_ids) || (body && typeof body !== 'object')) {
        console.warn("Invalid arguments: steedos_ids must be an array and body, if present, must be an object.");
        return;
    }

    const data = {
        toUsers: steedos_ids,
        pushTopic: 'workflow'
    };

    if (body) {
        data.data = body;
    }

    pushManager.send_message_by_raix_push(data, lang);
};

// TODO处理发送手机短信
pushManager.send_to_sms = function (to_user, message, current_user_info, spaceId) {
    // if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER) {
    //     return;
    // }

    // const isSmsNotificationEnabled = settings?.workflow?.sms_notification;
    // const userMobile = to_user?.mobile;
    // const isMobileVerified = to_user?.mobile_verified;

    // if (isSmsNotificationEnabled && userMobile && isMobileVerified) {
    //     const spaceUser = db.space_users.findOne(
    //         { user: to_user._id, space: spaceId },
    //         { fields: { sms_notification: 1 } }
    //     );

    //     if (spaceUser?.sms_notification) {
    //         return SMSQueue.send({
    //             RecNum: userMobile,
    //             msg: message,
    //             createdBy: current_user_info._id
    //         }, spaceId);
    //     }
    // }
};

//通知服务

pushManager.send_instance_notification = async function (send_from, instance, description, current_user_info, cc_user_ids, flowDoc) {
    if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER) {
        return;
    }

    const db = {
        users: await getCollection('users'),
        space_users: await getCollection('space_users')
    }

    try {
        const space_id = instance.space;
        const instance_id = instance._id;
        const flow = flowDoc || await uuflowManager.getFlow(instance.flow);
        const to_users = await pushManager.get_to_users(send_from, instance, cc_user_ids, current_user_info);

        const href = `${process.env.ROOT_URL}workflow/space/${space_id}/inbox/${instance_id}`;
        const body_style_start = "<div style='border:1px solid #bbb;padding:10px;'>";
        const body_style_end = "</div>";
        const current_step_name = instance.current_step_name;

        let nextApprove_usersname = null;
        if (['submit_pending_rejected_approve', 'submit_pending_rejected_applicant'].includes(send_from)) {
            const trace = instance.traces.find(t => !t.is_finished);
            const approve = trace.approves.find(a => !a.is_finished);
            nextApprove_usersname = approve.user_name;
        }

        const nextStep_type = await uuflowManager.getStep(instance, flow, instance.traces[instance.traces.length - 1].step).step_type;
        const lastApprove_judge = instance.traces[instance.traces.length - 2].approves[0].judge;
        const lastApprove_usersname = instance.traces[instance.traces.length - 2].approves.map(appr => appr.handler_name).join(",");

        const current_step = await uuflowManager.getStep(instance, flow, instance.traces[instance.traces.length - 2].step);

        let approves_description = null;
        if (['reassign_new_inbox_users', 'submit_completed_applicant', 'approved_completed_applicant', 'first_submit_applicant', 'first_submit_inbox', 'submit_pending_inbox'].includes(send_from)) {
            approves_description = instance.traces[instance.traces.length - 2].approves[0].description;

            if (current_step.step_type === "counterSign" && ["submit_completed_applicant", "submit_pending_inbox"].includes(send_from)) {
                const to_user_change = to_users[0].locale === 'zh-cn' ? 'zh-CN' : 'en';
                approves_description = instance.traces[instance.traces.length - 2].approves.map(appr => {
                    let judgeTranslation = t(`instance.judge.${appr.judge}`, {}, to_user_change);
                    return `${appr.user_name} : ${judgeTranslation},${appr.description}<br/>`;
                }).join('');
            }
        }

        let from_user = current_user_info;
        if (['reassign_new_inbox_users', 'first_submit_inbox', 'submit_pending_rejected_inbox', 'submit_pending_inbox', 'submit_completed_approve', 'submit_pending_rejected_approve', 'submit_terminate_approve', 'approved_completed_approve', 'rejected_completed_approve'].includes(send_from)) {
            from_user = await db.users.findOne({_id: instance.applicant});
        }

        const parameters = {
            send_from,
            applicant_name: instance.applicant_name,
            instance_name: instance.name,
            href,
            final_decision: instance.final_decision,
            description,
            state: instance.state,
            from_username: from_user.name,
            current_step_name,
            nextApprove_usersname,
            nextStep_type,
            approves_description,
            lastApprove_judge,
            lastApprove_usersname,
            current_user_name: current_user_info.name,
            currentStep_type: current_step.step_type
        };

        for (let to_user of to_users) {
            const lang = to_user.locale === 'zh-cn' ? 'zh-CN' : 'en';
            const inscribed = t('instance.email.inscribed', {}, lang);
            const footnote = `<p style='text-align:left;color:#bbb;'>${t('instance.email.footnote', {}, lang)}</p>`;

            parameters.to_username = to_user.name;

            const body = await pushManager.get_body(parameters, lang);
            const title = await pushManager.get_title(parameters, lang);
            const badge = await pushManager.get_badge(send_from, to_user._id);

            const push_body = {
                alertTitle: title.push,
                alert: body.push,
                space_id,
                instance_id,
                badge: badge || undefined,
                sound: "default",
                send_from
            };

            const content = `${body_style_start}${body.email}${inscribed}${body_style_end}${footnote}`;

            // Send Email
            await pushManager.send_email_to_SMTP(title.email, content, to_user, from_user);

            // Send Push Notification
            await pushManager.send_message([to_user.steedos_id], push_body, current_user_info, lang);

            // Send SMS
            if (['reassign_new_inbox_users', 'submit_pending_rejected_applicant_inbox', 'submit_pending_rejected_inbox', 'submit_pending_inbox', 'first_submit_inbox', 'return_pending_inbox'].includes(send_from)) {
                await pushManager.send_to_sms(to_user, pushManager.getSmsBody(parameters, lang), current_user_info, space_id);
            }
        }
    } catch (error) {
        console.error(error.stack);
    }
};


// 发送给当前用户
pushManager.send_message_current_user = function (user_info) {
    if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER) {
        return;
    }

    try {
        const badge = this.get_badge("current_user", user_info._id);
        const push_body = { badge };

        return this.send_message([user_info.steedos_id], push_body, user_info);
    } catch (error) {
        console.error(error.stack);
    }
};

// 发送push 并且内容只有待审核数量
pushManager.send_message_to_specifyUser = async function (send_from, to_user) {
    if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER) {
        return
    }
    const db = {
        users: await getCollection("users")
    }
    var badge, e, push_body, user_info;
    try {
        badge = await pushManager.get_badge(send_from, to_user);
        push_body = new Object;
        push_body["badge"] = badge;
        user_info = await db.users.findOne({
            _id: to_user
        }, {
            fields: {
                steedos_id: 1
            }
        });
        if (user_info) {
            return await pushManager.send_message([user_info.steedos_id], push_body);
        }
    } catch (error) {
        e = error;
        return console.error(e.stack);
    }
};

pushManager.triggerWebhook = async function (flowId, instance, currentApprove, action, fromUserId, toUserIds) {
    if (process.env.STEEDOS_DEBUG_DISABLE_PUSHMANAGER) {
        return;
    }
    const hasWebhooks = await pushManager.hasWebhooks(flowId);
    if (!hasWebhooks) {
        return;
    }

    const db = {
        users: await getCollection('users'),
        space_users: await getCollection('space_users'),
        webhooks: await getCollection('webhooks'),
        cfsInstances: await getCollection('cfs.instances.filerecord')
    };
  
    instance.attachments = (await db.cfsInstances.find({ 'metadata.instance': instance._id }).toArray()) || [];

    const fromUser = await db.users.findOne({ "_id": fromUserId }, { fields: { _id: 1, username: 1 } }) || {};
    const fromSpaceUser = await db.space_users.findOne({ "user": fromUserId }, { fields: { mobile: 1, email: 1 } }) || {};

    fromUser.mobile = fromSpaceUser.mobile || "";
    fromUser.email = fromSpaceUser.email || "";

    let toUsers = [];
    if (toUserIds.length > 0) {
        toUsers = await db.users.find({ "_id": { $in: toUserIds } }, { fields: { _id: 1, username: 1 } }).toArray();
        await Promise.all(toUsers.map(async (toUser) => {
            const toSpaceUser = await db.space_users.findOne({ "user": toUser._id }, { fields: { mobile: 1, email: 1 } }) || {};
            toUser.mobile = toSpaceUser.mobile || "";
            toUser.email = toSpaceUser.email || "";
        }));
    }

    const webhooks = await db.webhooks.find({
        flow: { $in: [flowId, null] },
        active: true
    }).toArray();

    for (const w of webhooks) {
        WebhookQueue.send({
            instance,
            current_approve: currentApprove,
            payload_url: w.payload_url,
            content_type: w.content_type,
            action,
            from_user: fromUser,
            to_users: toUsers || []
        });
    }
};

pushManager.hasWebhooks = async function (flowId) {
    const db = {
        webhooks: await getCollection('webhooks')
    };
    const webhookDocsCount = await db.webhooks.find({
        flow: { $in: [flowId, null] },
        active: true
    }).count();
    return webhookDocsCount > 0;
};


module.exports = pushManager;