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.basic.model.PageVo;
import com.ningdatech.pmapi.common.enumeration.ProjectProcessStageEnum;
import com.ningdatech.pmapi.common.helper.UserInfoHelper;
import com.ningdatech.pmapi.common.statemachine.util.StateMachineUtils;
import com.ningdatech.pmapi.projectdeclared.model.dto.DefaultDeclaredDTO;
import com.ningdatech.pmapi.projectdeclared.model.dto.ProjectConditionDTO;
import com.ningdatech.pmapi.projectdeclared.model.req.PrequalificationDeclaredListReq;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.manage.ProjectLibManage;
import com.ningdatech.pmapi.projectlib.model.dto.ProjectDTO;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.model.entity.ProjectInst;
import com.ningdatech.pmapi.projectlib.model.req.ProjectListReq;
import com.ningdatech.pmapi.projectlib.model.vo.ProjectLibListItemVO;
import com.ningdatech.pmapi.projectlib.service.IProjectInstService;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.staging.service.IProjectStagingService;
import com.ningdatech.pmapi.user.security.auth.model.UserFullInfoDTO;
import com.ningdatech.pmapi.user.util.LoginUserUtil;
import com.wflow.bean.entity.WflowModels;
import com.wflow.exception.BusinessException;
import com.wflow.workflow.bean.dto.OrgInfoDTO;
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 org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;

/**
 * @Classname ProqualificationDeclaredProjectManage
 * @Description
 * @Date 2023/2/13 14:48
 * @Author PoffyZhang
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class PrequalificationDeclaredProjectManage {

    private final IProjectService projectService;

    private final StateMachineUtils stateMachineUtils;

    private final ProcessInstanceService processService;

    private final ProcessModelService processModelService;

    private final IProjectInstService projectInstService;

    private final IProjectStagingService projectStagingService;

    private final ProjectLibManage projectLibManage;

    private final UserInfoHelper userInfoHelper;

    private final DefaultDeclaredProjectManage declaredProjectManage;

    private final DefaultDeclaredProjectManage defaultDeclaredProjectManage;

    /**
     * 提交预审
     *
     * @param dto
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public String startTheProcess(DefaultDeclaredDTO dto) {
        Long userId = LoginUserUtil.getUserId();
        VUtils.isTrue(Objects.isNull(userId)).throwMessage("获取登录用户失败!");

        ProjectDTO projectDto = dto.getProjectInfo();
        VUtils.isTrue(Objects.isNull(projectDto.getId())).throwMessage("提交失败 缺少项目ID!");
        Project projectInfo = projectService.getById(projectDto.getId());
        VUtils.isTrue(Objects.isNull(projectInfo)).throwMessage("提交失败 此项目不存在!");

        String regionCode = projectInfo.getAreaCode();

        WflowModels model = processModelService.getOne(Wrappers.lambdaQuery(WflowModels.class)
                .eq(WflowModels::getRegionCode, regionCode)
                .eq(WflowModels::getProcessType, ProjectProcessStageEnum.PROJECT_PREQUALIFICATION_APPROVAL_PROCESS.getCode())
                .last("limit 1"));

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

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

        //使用状态机 进入下一步 看看需不需要走省级审批
        try {
            stateMachineUtils.execute(projectInfo,stateMachineUtils.getProjectStatusPassEvent(projectInfo.getStatus()));
        } catch (Exception e) {
            log.error("项目 调用状态机出错:",e);
            throw new BusinessException(projectInfo.getId() +  "项目 调用状态机出错 :" + e.getMessage());
        }

        String instanceId = null;
        //如果是省级部门 需要联审的(申报金额大于1000万 并且是市级项目)
        if(ProjectStatusEnum.JOINT_REVIEW_BY_PROVINCIAL_DEPARTMENTS
                .getCode().equals(projectInfo.getStatus())){
            //入库暂存表 后续处理 对接外部接口
            projectInfo.setUpdateOn(LocalDateTime.now());
            if(projectStagingService.addByProject(projectInfo,"省级部门联审")
                    && projectService.updateById(projectInfo)){
                return "提交省级部门联审成功";
            }
            return "提交省级部门联审失败";
        }else if(ProjectStatusEnum.PRE_APPLYING
                .getCode().equals(projectInfo.getStatus())){
            //如果是非省级联审的项目 直接提交 预审
            ProcessStartParamsVo params = new ProcessStartParamsVo();
            params.setUser(declaredProjectManage.buildUser(userId));
            params.setProcessUsers(Collections.emptyMap());
            //放入条件判断的项目字段
            ProjectConditionDTO conditionDto = new ProjectConditionDTO();
            BeanUtils.copyProperties(projectInfo, conditionDto);
            dto.getFormData().putAll(
                    JSON.parseObject(JSON.toJSONString(conditionDto), new TypeReference<Map<String, Object>>() {
                    })
            );
            params.setFormData(dto.getFormData());

            // 获取发起单位、发起单位主管单位信息
            Map<String, OrgInfoDTO> orgModelMap = defaultDeclaredProjectManage.getOrgModelInfo(userId, model);
            instanceId = processService.newStartProcess(model.getProcessDefId(),model.getFormId(), params,orgModelMap);
            log.info("提交预审项目成功 【{}】", instanceId);

            //保存预审项目
            modifyProject(projectInfo, instanceId);

        }else{
            throw new BusinessException("项目状态 错误 project :" + JSON.toJSONString(projectInfo));
        }

        return "提交预审成功【" + instanceId + "】";
    }

    /**
     * 提交预审项目 时 更新信息
     *
     * @param project
     * @param instanceId
     */
    private void modifyProject(Project project, String instanceId) {
        //流程启动之后 入库项目 重要业务信息 用于列表查询 展示
        try {
            project.setUpdateOn(LocalDateTime.now());
            project.setInstCode(instanceId);
            //调用状态机 进入下一个通过状态
            stateMachineUtils.execute(project, stateMachineUtils.getProjectStatusPassEvent(project.getStatus()));
            projectService.updateById(project);

            //保存项目和实例的关系
            ProjectInst projectInst = new ProjectInst();
            projectInst.setProjectId(project.getId());
            projectInst.setInstCode(instanceId);
            projectInst.setCreatOn(LocalDateTime.now());
            projectInst.setUpdateOn(LocalDateTime.now());
            projectInst.setInstType(ProjectProcessStageEnum.PROJECT_PREQUALIFICATION_APPROVAL_PROCESS.getCode());
            projectInstService.save(projectInst);
        } catch (Exception e) {
            log.error("提交预审 项目信息修改 错误 ", e);
            throw new BusinessException("提交预审 项目信息修改 错误 :" + e.getMessage());
        }
    }

    /**
     * 查询项目库
     * @param preReq
     * @return
     */
    public PageVo<ProjectLibListItemVO> projectLibList(PrequalificationDeclaredListReq preReq) {
        //限定参数 复制bean
        ProjectListReq req = new ProjectListReq();
        BeanUtils.copyProperties(preReq,req);
        //项目阶段 状态 已定 待预审
        req.setStage(ProjectStatusEnum.NOT_APPROVED.getCode());
        req.setStatus(ProjectStatusEnum.PENDING_PREQUALIFICATION.getCode());
        Long userId = LoginUserUtil.getUserId();
        VUtils.isTrue(Objects.isNull(userId)).throwMessage("获取登录用户失败!");
        UserFullInfoDTO userFullInfo = userInfoHelper.getUserFullInfo(userId);
        //放入用户的单位
        req.setBuildOrgCode(userFullInfo.getOrganizationCode());
        return projectLibManage.projectLibList(req);
    }
}
