package com.ningdatech.pmapi.projectdeclared.manage;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.function.VUtils;
import com.ningdatech.pmapi.common.enumeration.ProjectProessStageEnum;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.projectdeclared.entity.dto.ConstructionPlanDto;
import com.ningdatech.pmapi.projectdeclared.entity.dto.ProjectConditionDto;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.wflow.bean.entity.WflowModels;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.bean.vo.ProcessStartParamsVo;
import com.wflow.workflow.service.ProcessInstanceService;
import com.wflow.workflow.service.ProcessModelService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;

/**
 * @Classname DeclaredProjectManage
 * @Description
 * @Date 2023/2/1 14:48
 * @Author PoffyZhang
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class ConstructionPlanManage {

    private final IProjectService projectService;

    private final ProcessInstanceService processService;

    private final ProcessModelService processModelService;

    private final StateMachineUtils stateMachineUtils;

    /**
     * 提交预审
     *
     * @param dto
     * @return
     */
    public String startTheProcess(ConstructionPlanDto dto) {
        Project projectInfo = projectService.getById(dto.getProjectId());

        VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!");

        String regionCode = projectInfo.getAreaCode();

        WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class)
                .eq(WflowModels::getRegionCode, regionCode)
                .eq(WflowModels::getFormName, ProjectProessStageEnum.CONSTRUCTION_PROJECT_APPROVAL_PROCESS.getDesc())
                .last("limit 1"));

        if (Objects.isNull(model)) {
            log.error("此 【{}】区域找不到 建设申报流程配置", regionCode);
            throw new BusinessException(String.format("此 【%s】区域找不到 建设申报流程配置", regionCode));
        }

        //首先要判断 项目当前状态 是不是 方案待申报
        VUtils.isTrue(!ProjectStatusEnum.PLAN_TO_BE_DECLARED.getCode().equals(projectInfo.getStatus()) ||
                        !ProjectStatusEnum.NOT_APPROVED.getCode().equals(projectInfo.getStage()))
                .throwMessage("提交失败 该项目不是 待预审状态或者未立项阶段");
        //TODO 再判断 该项目是否 真实走完 单位内部审批

        ProcessStartParamsVo params = new ProcessStartParamsVo();
        params.setUser(dto.getUser());
        params.setProcessUsers(Collections.emptyMap());
        //放入条件判断的项目字段
        ProjectConditionDto conditionDto = new ProjectConditionDto();
        BeanUtils.copyProperties(projectInfo, conditionDto);
        if (Objects.nonNull(conditionDto)) {
            dto.getFormData().putAll(
                    JSON.parseObject(JSON.toJSONString(conditionDto), new TypeReference<Map<String, Object>>() {
                    })
            );
        }
        params.setFormData(dto.getFormData());
        String instanceId = processService.startProcess(model.getProcessDefId(), params);
        log.info("建设方案项目申报成功 【{}】", instanceId);

        //保存建设项目
        modifyProject(projectInfo, instanceId, dto.getConstructionPlanFile());

        return instanceId;
    }

    /**
     * 提交预审项目 时 更新信息
     *
     * @param project
     * @param instanceId
     */
    private void modifyProject(Project project, String instanceId, String constructionPlanFile) {
        //流程启动之后 入库项目 重要业务信息 用于列表查询 展示
        try {
            project.setUpdateOn(LocalDateTime.now());
            project.setInstCode(instanceId);
            project.setConstructionPlanFile(constructionPlanFile);
            //调用状态机 进入下一个通过状态
            stateMachineUtils.execute(project, stateMachineUtils.getProjectStatusPassEvent(project.getStatus()));
            projectService.updateById(project);
        } catch (Exception e) {
            log.error("提交建设方案 项目信息修改 错误 ", e);
            throw new BusinessException("提交建设方案 项目信息修改 错误 :" + e.getMessage());
        }
    }
}
