const express = require("express");
const router = express.Router();
const { requireAuthentication } = require("@steedos/auth");
const _ = require('lodash');
const {
    update_instance_tasks,
} = require('../manager/instance_tasks_manager')
const UUFlowManager = require('../manager/uuflow_manager');
const { getCollection } = require('../utils/collection');
const approveManager = require('../manager/approve_manager');
const afterHook = require('./afterHook');

router.post('/api/workflow/v2/approve/save', requireAuthentication, afterHook, async function (req, res) {
    try {
        const userSession = req.user;
        const { approve } = req.body;
        const userId = userSession.userId;
        
        const ins_id = approve.instance;
        const trace_id = approve.trace;
        const approve_id = approve.id;
        const values = approve.values;
        const next_steps = approve.next_steps;
        const description = approve.description;
        const judge = approve.judge;

        const instancesCollection = await getCollection('instances');
        const usersCollection = await getCollection('users');
        const flowsCollection = await getCollection('flows');
        const formsCollection = await getCollection('forms');

        const instance = await instancesCollection.findOne({_id: ins_id}, {
            projection: {
                traces: 1,
                flow_version: 1,
                flow: 1,
                state: 1,
                form: 1,
                form_version: 1,
                values: 1,
                code: 1
            }
        });

        const traces = instance.traces;
        const current_trace = traces.find(t => t._id == trace_id);
        const current_approve = current_trace.approves.find(a => a._id == approve_id);

        // Validate instance status
        const current_user = await usersCollection.findOne({_id: userId}, {
            projection: { locale: 1 }
        });
        const lang = current_user.locale == 'zh-cn' ? 'zh-CN' : 'en';
        
        try {
            await UUFlowManager.isInstancePending(instance, lang);
            await UUFlowManager.isTraceNotFinished(current_trace);
            await UUFlowManager.isApproveNotFinished(current_approve);
            await UUFlowManager.isHandlerOrAgent(current_approve, userId);
        } catch (e) {
            console.log(e.stack);
            return res.status(200).send({});
        }

        const flow_version = instance.flow_version;
        const flow_id = instance.flow;
        const step_id = current_trace.step;

        const flow = await flowsCollection.findOne({_id: flow_id}, {
            projection: {
                current: 1,
                historys: 1
            }
        });

        let step = null;
        if (flow.current._id == flow_version) {
            step = flow.current.steps.find(s => s._id == step_id);
        } else {
            for (const h of flow.historys) {
                step = h.steps.find(s => s._id == step_id);
                if (step) break;
            }
        }

        if (!step) {
            return res.status(200).send({});
        }

        const step_type = step.step_type;
        const index = current_trace.approves.findIndex(a => a._id == approve_id);
        const key_str = `traces.$.approves.${index}.`;

        const permissions_values = await UUFlowManager.getApproveValues(
            values, 
            step.permissions, 
            instance.form, 
            instance.form_version
        );

        const change_values = await approveManager.getChangeValues(instance.values, permissions_values);
        const setObj = {
            values: _.extend((instance.values || {}), permissions_values)
        };

        if (!_.isEmpty(change_values)) {
            const values_history = current_approve.values_history || [];
            values_history.push({
                values: change_values,
                create: new Date()
            });
            setObj[key_str + 'values_history'] = values_history;
        }

        setObj[key_str + 'is_read'] = true;
        setObj[key_str + 'read_date'] = new Date();
        setObj[key_str + 'values'] = setObj.values;
        setObj[key_str + 'description'] = description;
        setObj[key_str + 'next_steps'] = next_steps;
        setObj[key_str + 'judge'] = (step_type == "submit" || step_type == "start") ? "submitted" : judge;
        setObj.modified = new Date();
        setObj.modified_by = userId;

        // Calculate instance name
        const form = await formsCollection.findOne({_id: instance.form});
        const form_v = await UUFlowManager.getFormVersion(form, instance.form_version);
        const name_forumla = form_v.name_forumla;
        
        if (name_forumla) {
            setObj.name = await UUFlowManager.getInstanceName(instance, setObj.values);
        }

        const result = await instancesCollection.updateOne({
            _id: ins_id,
            "traces._id": trace_id
        }, {
            $set: setObj
        });

        await update_instance_tasks(ins_id, trace_id, approve_id);
        
        res.status(200).send({
            'instance': result
        });
    } catch (error) {
        console.error(error);
        res.status(200).send({
            error: error.message
        });
    }
});
exports.default = router;