package cn.axzo.workflow.server.controller.web;

import cn.axzo.framework.domain.ServiceException;
import cn.axzo.workflow.client.feign.bpmn.ProcessInstanceApi;
import cn.axzo.workflow.common.model.dto.VariableObjectDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceAbortDTO;
import cn.axzo.workflow.common.model.request.bpmn.process.BpmnProcessInstanceQueryDTO;
import cn.axzo.workflow.common.model.request.form.definition.FormContentSearchDTO;
import cn.axzo.workflow.common.model.request.form.instance.FormInstanceSearchDTO;
import cn.axzo.workflow.common.model.response.bpmn.process.BpmnProcessInstanceVO;
import cn.axzo.workflow.common.model.response.bpmn.process.ProcessNodeDetailVO;
import cn.axzo.workflow.core.engine.cmd.CustomGetProcessInstanceVariablesToObjectCmd;
import cn.axzo.workflow.core.repository.entity.ExtAxBpmnFormRelation;
import cn.axzo.workflow.core.service.BpmnProcessInstanceService;
import cn.axzo.workflow.core.service.ExtAxBpmnFormRelationService;
import cn.axzo.workflow.core.service.support.FlowNodeForecastService;
import cn.axzo.workflow.form.service.FormDefinitionService;
import cn.axzo.workflow.server.common.annotation.RepeatSubmit;
import cn.axzo.workflow.server.common.util.ShellUtil;
import cn.axzo.workflow.server.xxljob.EsIndexOperationJobHandler;
import cn.axzo.workflow.server.xxljob.SpecifyProcessInstanceSyncEsJobHandler;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.impl.interceptor.CommandExecutor;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.form.api.FormDefinition;
import org.flowable.form.api.FormInfo;
import org.flowable.form.api.FormInstanceInfo;
import org.flowable.form.api.FormRepositoryService;
import org.flowable.form.api.FormService;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.PropertyPlaceholderHelper;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.InputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import static cn.axzo.workflow.common.enums.BpmnProcessInstanceResultEnum.PROCESSING;

/**
 * 测试接口
 *
 * @author wangli
 * @since 2023/10/10 13:59
 */
@Slf4j
@RequestMapping("/web/v1/api")
@RestController
@Validated
public class TestController {
    @Value("${spring.profiles.active}")
    private String profile;
    @Autowired
    private FlowNodeForecastService forecastService;
    @Autowired
    private BpmnProcessInstanceService instanceService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessInstanceApi processInstanceApi;
    @Autowired
    private BpmnProcessInstanceService bpmnProcessInstanceService;
    @Resource
    private FormService formService;
    @Resource
    private FormRepositoryService formRepositoryService;
    @Resource
    private FormDefinitionService formDefinitionService;
    @Resource
    private ExtAxBpmnFormRelationService bpmnFormRelationService;
    //    @Autowired
//    private WorkflowCoreService workflowCoreService;
//    @Autowired
//    private WorkflowManageService workflowManageService;
    @Resource
    private SpringProcessEngineConfiguration processEngineConfiguration;
    @Resource
    private EsIndexOperationJobHandler esIndexOperationJobHandler;
    @Resource
    private SpecifyProcessInstanceSyncEsJobHandler specifyProcessInstanceSyncEsJobHandler;
    @Resource
    private TaskService taskService;

    @RepeatSubmit
    @GetMapping("/test")
    public void test(@RequestParam String processInstanceId, @RequestParam(required = false) String taskDefinitionKey, @RequestParam(required = false) Boolean containSelf) {
        List<FlowElement> flowElements = forecastService.performProcessForecasting(processInstanceId, null, taskDefinitionKey, containSelf);
        System.out.println("flowElements = " + flowElements);
    }

    @RepeatSubmit
    @GetMapping("/test2")
    public void test2(@RequestParam String processInstanceId) {
        List<ProcessNodeDetailVO> detailVOS = instanceService.getProcessInstanceNodeForecast(processInstanceId, "296");
        System.out.println("detailVOS = " + detailVOS);
    }

    /**
     * 操作 act_ge_bytearray
     *
     * @param processInstanceId
     * @return
     */
    @GetMapping("/test3")
    public String test3(@RequestParam String processInstanceId) {
        Deployment deploy =
                repositoryService.createDeployment().addBytes("自定义资源", processInstanceId.getBytes()).deploy();
        InputStream is = repositoryService.getResourceAsStream(deploy.getId(), "自定义资源");
        byte[] bytes = IoUtil.readInputStream(is, "自定义资源");
        return new String(bytes);
    }

    @GetMapping("/test4")
    public String test4() {
        BpmnProcessInstanceQueryDTO query = new BpmnProcessInstanceQueryDTO();
        query.setProcessInstanceId("202311131646000000000");
        CommonResponse<BpmnProcessInstanceVO> processInstanceVO = processInstanceApi.getProcessInstanceVO(query);
        return processInstanceVO.getData().getName();
    }

    @GetMapping("/system/operation/batch/abort")
    public CommonResponse<Boolean> systemOperation(Long timestamp) {
        if (Objects.isNull(timestamp)) {
            timestamp = 1706198400000L;
        }
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
                .processInstanceBusinessStatus(PROCESSING.getStatus())
                .startedBefore(new Date(timestamp))
                .unfinished()
                .list();
        log.info("待系统中止的流程实例数: {}", list.size());
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        list.forEach(i -> {
            executorService.submit(() -> {
                try {
                    log.info("当前中止的流程: {}", i.getId());
                    BpmnProcessInstanceAbortDTO abort = new BpmnProcessInstanceAbortDTO();
                    abort.setProcessInstanceId(i.getId());
                    abort.setReason("系统超时中止");
                    bpmnProcessInstanceService.abortProcessInstance(abort);
                } catch (Exception e) {
                    log.warn("系统批量中止流程: {}, 发生异常: {}", i.getId(), e.getMessage());
                }
            });
        });
        return CommonResponse.success(true);
    }

    /*@GetMapping("/create")
    public CommonResponse<String> test5(@RequestParam(required = false) Boolean sync) {
        BpmnProcessInstanceCreateDTO dto = new BpmnProcessInstanceCreateDTO();
        dto.setProcessDefinitionKey("1");
        dto.setCooperationOrg(new CooperationOrgDTO());
        dto.setBusinessKey("businessKey");
        dto.setInitiator(new BpmnTaskDelegateAssigner());
        if (Objects.nonNull(sync)) {
            if (sync) {
                workflowCoreService.sync();
            } else {
                workflowCoreService.async();
            }
        }
        return CommonResponse.success(workflowCoreService.createProcessInstance(dto));
    }

    @GetMapping("/approve")
    public CommonResponse<Boolean> test6(@RequestParam(required = false) Boolean sync, @RequestParam String taskId) {
        if (Objects.nonNull(sync)) {
            if (sync) {
                workflowCoreService.sync();
            } else {
                workflowCoreService.async();
            }
        }
        BpmnTaskAuditDTO dto = new BpmnTaskAuditDTO();
        dto.setTaskId(taskId);
        BpmnTaskDelegateAssigner approver = new BpmnTaskDelegateAssigner("2002456", "3", "彭建伦", "9000586", "374", "6064", "https://axzo-app.oss-cn-chengdu.aliyuncs.com/face/face_dev/f5f5634ff6e84bfd9291b8e1a8ad215d.jpg");
        dto.setApprover(approver);
        return CommonResponse.success(workflowCoreService.approveTask(dto));
    }

    @GetMapping("/get")
    public CommonResponse<BpmnProcessInstanceVO> test7(@RequestParam(required = false) Boolean sync, @RequestParam String processInstanceId) {
        if (Objects.isNull(sync)) {
            throw new RuntimeException("sync 参数不能为空");
        }
        if (Objects.nonNull(sync)) {
            if (sync) {
                workflowCoreService.sync();
            } else {
                workflowCoreService.async();
            }
        }
        BpmnProcessInstanceQueryDTO dto = new BpmnProcessInstanceQueryDTO();
        dto.setProcessInstanceId(processInstanceId);
        dto.setHasVariable(true);
//        return CommonResponse.success(workflowCoreService.getProcessInstanceVO(dto));
        return CommonResponse.success(workflowCoreService.getProcessInstanceVO(dto));
    }

    @GetMapping("/get/vars")
    public CommonResponse<Map<String, Object>> test8(@RequestParam(required = false) Boolean sync, @RequestParam String processInstanceId) {
        if (Objects.isNull(sync)) {
            throw new RuntimeException("sync 参数不能为空");
        }
        if (Objects.nonNull(sync)) {
            if (sync) {
                workflowCoreService.sync();
            } else {
                workflowCoreService.async();
            }
        }
        return CommonResponse.success(workflowCoreService.getProcessVariables(processInstanceId, null));
    }

    @GetMapping("/create/var")
    public CommonResponse<Void> test9(@RequestParam(required = false) Boolean sync, @RequestParam String processInstanceId) {
        if (Objects.isNull(sync)) {
            throw new RuntimeException("sync 参数不能为 null");
        }
        if (Objects.nonNull(sync)) {
            if (sync) {
                workflowCoreService.sync();
            } else {
                workflowCoreService.async();
            }
        }
        RestBpmnProcessVariable variable = new RestBpmnProcessVariable();
        variable.setName("testVar");
        variable.setValue("testValue");
//        workflowCoreService.createVariable(processInstanceId, variable);
        return CommonResponse.success(null);
    }

    @GetMapping("/batch/abort")
    public CommonResponse test10(@RequestParam(required = false) Boolean sync) {
        if (Objects.isNull(sync)) {
            throw new RuntimeException("sync 参数不能为 null");
        }
        if (Objects.nonNull(sync)) {
            if (sync) {
                workflowCoreService.sync();
            } else {
                workflowCoreService.async();
            }
        }
        List<BpmnProcessInstanceAbortDTO> dtos = new ArrayList<>();
        BpmnProcessInstanceAbortDTO abort = new BpmnProcessInstanceAbortDTO();
        abort.setProcessInstanceId("1");
        abort.setTenantId("2");
        abort.setReason("reason");
        dtos.add(abort);
        workflowCoreService.batchAbortProcessInstance(dtos);
        return CommonResponse.success(dtos);
    }

    @GetMapping("/tenant/get/ids")
    public CommonResponse<List<String>> test11() {
        List<String> tenantIds = workflowManageService.sync().getTenantIds();
        return CommonResponse.success(tenantIds);
    }*/

    @GetMapping("log")
    public String log(@RequestParam String keyword, @RequestParam(required = false) String date, @RequestParam(required = false) String grepKeyword) throws Exception {
        if (!StringUtils.hasText(keyword)) {
            return "命令不能为空";
        }
        if (StringUtils.hasText(date)) {
            return ShellUtil.grepLog(profile, keyword, StringUtils.hasText(date) ? DateUtil.parseDate(date) : new Date(), grepKeyword);
        }
        String s = ShellUtil.grepRealTimeLog(profile, keyword);
        if (StringUtils.hasText(s)) {
            return s;
        }
        return ShellUtil.grepLog(profile, keyword, StringUtils.hasText(date) ? DateUtil.parseDate(date) : new Date(), grepKeyword);
    }

    @GetMapping("form")
    public CommonResponse<FormInfo> getForm(@RequestParam String definitionId, @RequestParam(required = false) String processInstanceId, @RequestParam(required = false) String taskId) {
//        FormInfo startFormModel = bpmnProcessInstanceService.getStartFormModel(definitionId, processInstanceId);
//        formService.getFormInstanceModelByKey("we", null, null, null);
        FormContentSearchDTO contentSearch = new FormContentSearchDTO();
        contentSearch.setProcessInstanceId(processInstanceId);
        contentSearch.setTaskId(taskId);
        contentSearch.setTenantId("400");
        FormInfo formInfo = formDefinitionService.getFormInfo(contentSearch);
        FormInfo we = formService.getFormModelWithVariablesByKey("we", null, null);
        FormInstanceInfo we1 = formService.getFormInstanceModelByKey("we", StringUtils.hasText(taskId) ? taskId : null, null, null, "", false);
        FormInfo formModelByKey = formRepositoryService.getFormModelByKey("we");
        FormInfo startFormModel = runtimeService.getStartFormModel(definitionId, processInstanceId);
        return CommonResponse.success(null);
    }

    /**
     * 获取表单实例
     *
     * @param dto
     * @return
     */
    @PostMapping("/form/get")
    public CommonResponse<FormInstanceInfo> getFormInstance(@RequestBody FormInstanceSearchDTO dto) {
        if (!StringUtils.hasText(dto.getProcessInstanceId()) && !StringUtils.hasText(dto.getTaskId())) {
            throw new ServiceException("不允许同时为空");
        }
        HistoricProcessInstance instance;
        if (StringUtils.hasText(dto.getProcessInstanceId())) {
            instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult();
            dto.setTenantId(instance.getTenantId());
        } else {
            HistoricTaskInstance task = historyService.createHistoricTaskInstanceQuery().taskId(dto.getTaskId()).singleResult();
            instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
            dto.setTenantId(instance.getTenantId());
        }
        ExtAxBpmnFormRelation relation = bpmnFormRelationService.queryByBpmnDefinitionId(instance.getProcessDefinitionId());
        FormDefinition formDefinition = formRepositoryService.createFormDefinitionQuery().deploymentId(relation.getFormDeploymentId()).singleResult();
        FormInstanceInfo formInstance = formService.getFormInstanceModelById(formDefinition.getId(), dto.getTaskId(), dto.getProcessInstanceId(), dto.getVariables(), relation.getTenantId(), false);
        return CommonResponse.success(formInstance);
    }

    /**
     * 表达式测试
     *
     * @param expression
     * @param variables
     * @return
     */
    @PostMapping("/expression/testing")
    public CommonResponse<String> parseExpression(@RequestParam String expression, @RequestBody Map<String, String> variables) {
//        ExpressionManager expressionManager = processEngineConfiguration.getExpressionManager();
//        Expression exp = expressionManager.createExpression(expression);
//        VariableContainerWrapper variableContainer = new VariableContainerWrapper(variables);
//        String stringFromField = ExpressionUtils.getStringFromField(exp, variableContainer);
//        Object value = exp.getValue(variableContainer);

        PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("${", "}");
        Properties properties = new Properties();
        variables.forEach(properties::setProperty);

        // 自定义PlaceholderResolver实现类，用于处理占位符找不到对应值时返回空字符串
        PropertyPlaceholderHelper.PlaceholderResolver resolver = placeholder -> properties.getProperty(placeholder, "");
        String value = propertyPlaceholderHelper.replacePlaceholders(expression, resolver);
        return CommonResponse.success(value);
    }

    @GetMapping("/es/index")
    public CommonResponse<String> esIndex(@RequestParam String str) {
        esIndexOperationJobHandler.execute(str);
        return CommonResponse.success();
    }

    @GetMapping("/es/sync")
    public CommonResponse<String> syncProcessInstanceToEs(@RequestParam String processInstanceId) {
        specifyProcessInstanceSyncEsJobHandler.execute(processInstanceId);
        return CommonResponse.success();
    }

    @GetMapping("/wps/variables")
    public CommonResponse<String> getWpsVariables(@RequestParam String processInstanceId) {
        CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutor();
        List<VariableObjectDTO> wpsVariables =
                commandExecutor.execute(new CustomGetProcessInstanceVariablesToObjectCmd(processInstanceId));
        return CommonResponse.success(JSON.toJSONString(wpsVariables));
    }

    @GetMapping("/task/complete")
    public CommonResponse<Boolean> taskComplete(@RequestParam String taskId) {
        taskService.complete(taskId);
        return CommonResponse.success(true);
    }
}

