package cn.axzo.workflow.form.service.impl;

import cn.axzo.workflow.common.code.BpmnTaskRespCode;
import cn.axzo.workflow.common.exception.WorkflowEngineException;
import cn.axzo.workflow.common.model.request.form.instance.FormContentUpdateDTO;
import cn.axzo.workflow.common.model.request.form.instance.FormInstanceSearchDTO;
import cn.axzo.workflow.common.model.response.form.instance.FormInstanceVO;
import cn.axzo.workflow.form.service.FormInstanceService;
import cn.axzo.workflow.form.service.converter.FormInstanceConverter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.HistoryService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.form.api.FormInstanceInfo;
import org.flowable.form.api.FormRepositoryService;
import org.flowable.form.api.FormService;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

import static cn.axzo.workflow.common.code.BpmnInstanceRespCode.PROCESS_INSTANCE_ID_NOT_EXISTS;


/**
 * 表单实例 Service 实现
 *
 * @author wangli
 * @since 2023/7/21 15:27
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FormInstanceServiceImpl implements FormInstanceService {

    @Resource
    private FormService formService;
    @Resource
    private TaskService taskService;
    @Resource
    private FormInstanceConverter formInstanceConverter;
    @Resource
    private HistoryService historyService;
    @Resource
    private FormRepositoryService formRepositoryService;

    @Override
    public void updateFormContent(FormContentUpdateDTO dto) {
        TaskQuery query = taskService.createTaskQuery().taskId(dto.getTaskId());
        if (Objects.nonNull(dto.getTenantId())) {
            query.taskTenantId(dto.getTenantId());
        }
        Task task = query.singleResult();
        if (Objects.isNull(task)) {
            throw new WorkflowEngineException(BpmnTaskRespCode.TASK_COMPLETE_FAIL_NOT_EXISTS);
        }
        if (!Objects.equals(dto.getUserId(), task.getAssignee())) {
            throw new WorkflowEngineException(BpmnTaskRespCode.TASK_COMPLETE_FAIL_ASSIGN_NOT_SELF);
        }

        if (Objects.nonNull(task.getProcessInstanceId())) {
            formService.saveFormInstanceByFormDefinitionId(dto.getFormVariables(), dto.getFormDefinitionId(),
                    dto.getTaskId(),
                    task.getProcessInstanceId(),
                    task.getProcessDefinitionId(), task.getTenantId(), null);
        } else {
            formService.saveFormInstanceWithScopeId(dto.getFormVariables(), dto.getFormDefinitionId(), dto.getTaskId(),
                    task.getScopeId(), task.getScopeType(), task.getScopeDefinitionId(), task.getTenantId(), null);
        }
    }

    @Override
    public FormInstanceVO getFormInstanceInfo(FormInstanceSearchDTO dto) {
        HistoricProcessInstance instance = historyService.createHistoricProcessInstanceQuery().processInstanceId(dto.getProcessInstanceId()).singleResult();
        if (Objects.isNull(instance)) {
            throw new WorkflowEngineException(PROCESS_INSTANCE_ID_NOT_EXISTS, dto.getProcessInstanceId());
        }

        String processDefinitionKey = instance.getProcessDefinitionKey();

        FormInstanceInfo formInstanceInfo = formService.getFormInstanceModelByKey(processDefinitionKey, dto.getTaskId(), dto.getProcessInstanceId(), dto.getVariables(), instance.getTenantId(), true);
        return formInstanceConverter.toVo(formInstanceInfo);
    }
}
