/*
 * @Author: baozhoutao@steedos.com
 * @Date: 2022-09-15 13:09:51
 * @LastEditors: sunhaolin@hotoa.com
 * @LastEditTime: 2023-10-08 Updated to use new utils and async/await
 * @Description: Refactored to use async/await and new utils
 */
const express = require("express");
const router = express.Router();
const { requireAuthentication } = require("@steedos/auth");
const _ = require("lodash");
const {
    remove_many_instance_tasks,
} = require('../manager/instance_tasks_manager')
const PermissionManager = require('../manager/permission_manager');
const UUFlowManager = require('../manager/uuflow_manager');
const pushManager = require('../manager/push_manager');
const { _makeNewID, getCollection } = require('../utils/collection');

/**
 * Terminate a workflow instance
 */
router.post("/api/workflow/v2/instance/terminate", requireAuthentication, async function (req, res) {
    try {
        const userSession = req.user;
        const { terminate_reason, instance_id } = req.body;
        
        if (!terminate_reason) {
            throw new Error("还未填写强制结束申请单的理由，操作失败");
        }
        if (!instance_id) {
            throw new Error("instance_id is required");
        }

        const current_user_info = userSession;
        const current_user = current_user_info.userId;

        // Get necessary data
        const instance = await UUFlowManager.getInstance(instance_id);
        const space_id = instance.space;
        const flow_id = instance.flow;

        const [space, flow] = await Promise.all([
            UUFlowManager.getSpace(space_id),
            UUFlowManager.getFlow(flow_id)
        ]);

        // Validate instance status
        await UUFlowManager.isInstancePending(instance);

        // Get user and org info
        const space_user = await UUFlowManager.getSpaceUser(space_id, current_user);
        const space_user_org_info = await UUFlowManager.getSpaceUserOrgInfo(space_user);

        // Find flow version matching instance
        const flow_vers = [flow.current, ...(flow.historys || [])];
        const instance_flow_ver = flow_vers.find(f_ver => f_ver._id === instance.flow_version);
        if (!instance_flow_ver) {
            throw new Error("未找到申请单对应流程版本");
        }

        // Find end step
        const flow_ver_end_step = instance_flow_ver.steps.find(step => step.step_type === "end");
        if (!flow_ver_end_step) {
            throw new Error("流程版本中未找到结束节点");
        }

        // Check permissions
        const permissions = await PermissionManager.getFlowPermissions(flow_id, current_user);
        const hasPermission = permissions.includes("admin") || 
                             space.admins.includes(current_user) || 
                             instance.submitter === current_user || 
                             instance.applicant === current_user;
        if (!hasPermission) {
            throw new Error("无权终止此申请单");
        }

        const now = new Date();
        const setObj = {};
        const instance_trace = instance.traces.find(trace => !trace.is_finished);
        if (!instance_trace) {
            throw new Error("未找到未完成的流程轨迹");
        }

        // Process traces and approves
        const traces = _.cloneDeep(instance.traces);
        const finishedApproveIds = [];

        for (const trace of traces) {
            if (!trace.is_finished) {
                trace.is_finished = true;
                trace.finish_date = now;

                for (const approve of trace.approves) {
                    if (!approve.is_finished) {
                        approve.is_finished = true;
                        approve.finish_date = now;
                        approve.judge = null;
                        approve.description = null;
                        finishedApproveIds.push(approve._id);
                    }
                }

                // Add new terminate approve
                const newApprove = {
                    _id: _makeNewID(),
                    instance: instance_id,
                    trace: instance_trace._id,
                    is_finished: true,
                    user: current_user,
                    user_name: current_user_info.name,
                    handler: current_user,
                    handler_name: current_user_info.name,
                    handler_organization: space_user_org_info.organization,
                    handler_organization_name: space_user_org_info.organization_name,
                    handler_organization_fullname: space_user_org_info.organization_fullname,
                    start_date: now,
                    finish_date: now,
                    due_date: instance_trace.due_date,
                    read_date: now,
                    judge: "terminated",
                    is_read: true,
                    description: terminate_reason,
                    is_error: false,
                    values: {},
                    cost_time: 0 // Will be calculated below
                };
                newApprove.cost_time = newApprove.finish_date - newApprove.start_date;
                trace.approves.push(newApprove);
            }
        }

        // Add new terminate trace
        const newTrace = {
            _id: _makeNewID(),
            instance: instance_id,
            previous_trace_ids: [instance_trace._id],
            is_finished: true,
            step: flow_ver_end_step._id,
            name: flow_ver_end_step.name,
            start_date: now,
            finish_date: now,
            judge: "terminated"
        };

        // Prepare update object
        const old_inbox_users = instance.inbox_users || [];
        const old_cc_users = instance.cc_users || [];
        const old_outbox_users = instance.outbox_users || [];
        
        const tempUsers = [];
        instance_trace.approves.forEach(approve => {
            tempUsers.push(approve.user);
            tempUsers.push(approve.handler);
        });

        setObj.state = "completed";
        setObj.final_decision = "terminated";
        setObj.outbox_users = _.uniq([...old_outbox_users, ...tempUsers]);
        setObj.inbox_users = [];
        setObj.cc_users = [];
        setObj.modified = now;
        setObj.modified_by = current_user;
        setObj.traces = [...traces, newTrace];
        setObj.current_step_name = flow_ver_end_step.name;
        setObj.current_step_auto_submit = false;

        // Update instance
        const instancesCollection = await getCollection('instances');
        const result = await instancesCollection.updateOne(
            { _id: instance_id },
            { $set: setObj }
        );

        if (result.modifiedCount > 0) {
            // Remove instance tasks
            await remove_many_instance_tasks(finishedApproveIds);

            // Send notifications
            const updatedInstance = await UUFlowManager.getInstance(instance_id);
            await pushManager.send_instance_notification(
                "submit_terminate_applicant",
                updatedInstance,
                terminate_reason,
                current_user_info
            );

            // Notify all involved users
            const usersToNotify = _.uniq([...old_inbox_users, ...old_cc_users]);
            await Promise.all(
                usersToNotify.map(user_id => 
                    pushManager.send_message_to_specifyUser("terminate_approval", user_id)
                )
            );

            // Trigger webhook
            await pushManager.triggerWebhook(
                updatedInstance.flow,
                updatedInstance,
                {},
                "terminate",
                current_user,
                []
            );
        }

        res.status(200).send({});
    } catch (error) {
        console.error(error);
        res.status(200).send({
            error: error.message,
        });
    }
});

exports.default = router;