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

import cn.axzo.workflow.common.model.request.form.definition.FormDefinitionDTO;
import cn.axzo.workflow.common.model.request.form.definition.FormDefinitionUpdateDTO;
import cn.axzo.workflow.common.model.response.form.definition.FormDefinitionVO;
import cn.axzo.workflow.core.common.exception.WorkflowEngineException;
import cn.axzo.workflow.core.service.FormDefinitionService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Model;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static cn.axzo.workflow.core.common.code.FormDefinitionRespCode.FORM_DEFINITION_NOT_EXISTS;
import static cn.axzo.workflow.core.common.code.FormDefinitionRespCode.FORM_DEFINITION_PARSER_ERROR;
import static cn.axzo.workflow.core.common.code.FormModelRespCode.FORM_MODEL_ID_NOT_EXISTS;
import static cn.axzo.workflow.core.common.code.FormModelRespCode.FORM_MODEL_NOT_EXISTS;


/**
 * 表单定义 Service 实现
 *
 * @author wangli
 * @since 2023/7/19 16:47
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FormDefinitionServiceImpl implements FormDefinitionService {

    @Resource
    private RepositoryService repositoryService;
    @Resource
    private ObjectMapper objectMapper;

    @Override
    public FormDefinitionVO get(String formModelId, @Nullable String tenantId) {
        Model model = repositoryService.getModel(formModelId);

        if (Objects.isNull(model)) {
            throw new WorkflowEngineException(FORM_MODEL_ID_NOT_EXISTS, formModelId);
        }
        if (Objects.nonNull(tenantId) && !Objects.equals(model.getTenantId(), tenantId)) {
            throw new WorkflowEngineException(FORM_MODEL_NOT_EXISTS);
        }
        FormDefinitionVO vo = null;
        try {
            vo = objectMapper.readValue(repositoryService.getModelEditorSource(model.getId()),
                    FormDefinitionVO.class);
        } catch (Exception e) {
            e.printStackTrace();
            throw new WorkflowEngineException(FORM_DEFINITION_NOT_EXISTS);
        }
        vo.setKey(model.getKey());
        vo.setName(model.getName());
        vo.setCategory(model.getCategory());
        vo.setVersion(model.getVersion());
        vo.setTenantId(model.getTenantId());
        return vo;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateFormDefinition(FormDefinitionUpdateDTO dto) {
        Model model = repositoryService.getModel(dto.getFormModelId());
        if (Objects.isNull(model)) {
            throw new WorkflowEngineException(FORM_MODEL_ID_NOT_EXISTS, dto.getFormModelId());
        }
        if (Objects.nonNull(dto.getTenantId()) && !Objects.equals(model.getTenantId(), dto.getTenantId())) {
            throw new WorkflowEngineException(FORM_MODEL_ID_NOT_EXISTS, dto.getFormModelId());
        }
        FormDefinitionDTO formDefinition = dto.getFormDefinition();
        formDefinition.setKey(model.getKey());
        formDefinition.setName(model.getName());
        formDefinition.setVersion(model.getVersion());

        try {
            repositoryService.addModelEditorSource(model.getId(),
                    objectMapper.writeValueAsString(formDefinition).getBytes());
        } catch (Exception e) {
            throw new WorkflowEngineException(FORM_DEFINITION_PARSER_ERROR);
        }
        repositoryService.saveModel(model);
    }

}
