package com.zt.plat.module.qms.resource.device.service;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.security.core.LoginUser;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.bpm.api.task.BpmProcessInstanceApi;
import com.zt.plat.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import com.zt.plat.module.qms.api.task.BMPCallbackInterface;
import com.zt.plat.module.qms.api.task.dto.QmsBpmDTO;
import com.zt.plat.module.qms.common.data.dal.dataobject.DataCommonType;
import com.zt.plat.module.qms.common.data.service.DataKeyCheckService;
import com.zt.plat.module.qms.common.data.service.DataOpinionService;
import com.zt.plat.module.qms.common.dic.service.DictionaryBusinessService;
import com.zt.plat.module.qms.enums.QmsBpmConstant;
import com.zt.plat.module.qms.enums.QmsCommonConstant;
import com.zt.plat.module.qms.resource.device.common.DeviceConstant;
import com.zt.plat.module.qms.resource.device.controller.vo.DevicePeriodCheckPlanRespVO;
import com.zt.plat.module.qms.resource.device.controller.vo.DevicePeriodCheckPlanPageReqVO;
import com.zt.plat.module.qms.resource.device.controller.vo.DevicePeriodCheckPlanSaveReqVO;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DevicePeriodCheckPlanDO;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DevicePeriodCheckDO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.annotation.Validated;

import java.text.SimpleDateFormat;
import java.util.*;

import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;

import com.zt.plat.module.qms.resource.device.dal.mapper.DevicePeriodCheckPlanMapper;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.zt.plat.framework.common.util.collection.CollectionUtils.convertList;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.DEVICE_PERIOD_CHECK_PLAN_NOT_EXISTS;
import static com.zt.plat.module.qms.enums.QmsBpmConstant.BPM_CALLBACK_BEAN_NAME;

/**
 * 设备-期间核查计划 Service 实现类
 *
 * @author 后台管理-1
 */
@Service("devicePeriodCheckPlanService")
@Validated
@Slf4j
public class DevicePeriodCheckPlanServiceImpl implements DevicePeriodCheckPlanService, BMPCallbackInterface {

    @Resource private DevicePeriodCheckPlanMapper devicePeriodCheckPlanMapper;
    @Resource private DevicePeriodCheckService devicePeriodCheckService;
    @Resource private DictionaryBusinessService dictionaryBusinessService;
    @Resource private BpmProcessInstanceApi bpmProcessInstanceApi;
    @Resource private DataKeyCheckService dataKeyCheckService;
    @Resource private DataOpinionService dataOpinionService;
    private final String wfDicKey = "DevicePeriodCheckPlanWfKey";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public DevicePeriodCheckPlanRespVO createPlanDevice(String checkYear) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        String userName = SecurityFrameworkUtils.getLoginUserNickname();
        String title = userName + "的"+checkYear+"年度期间核查计划";
        DevicePeriodCheckPlanDO entity = new DevicePeriodCheckPlanDO();
        entity.setCheckYear(checkYear);
        entity.setTitle(title);
        entity.setApplyUserName(userName);
        entity.setFlowStatus(QmsCommonConstant.NOT_START);
        entity.setCheckTarget(DeviceConstant.PERIOD_CHECK_TAGET_DEVICE);
        devicePeriodCheckPlanMapper.insert(entity);
        devicePeriodCheckService.createListByPlanDevice(entity);
        return BeanUtils.toBean(entity, DevicePeriodCheckPlanRespVO.class);
    }

    @Override
    public DevicePeriodCheckPlanRespVO createPlanMaterial(String checkYear) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        String userName = SecurityFrameworkUtils.getLoginUserNickname();
        String title = userName + "的"+checkYear+"年度期间核查计划";
        DevicePeriodCheckPlanDO entity = new DevicePeriodCheckPlanDO();
        entity.setCheckYear(checkYear);
        entity.setTitle(title);
        entity.setApplyUserName(userName);
        entity.setFlowStatus(QmsCommonConstant.NOT_START);
        entity.setCheckTarget(DeviceConstant.PERIOD_CHECK_TAGET_MATERIAL);
        devicePeriodCheckPlanMapper.insert(entity);
        devicePeriodCheckService.createListByPlanMaterial(entity);
        return BeanUtils.toBean(entity, DevicePeriodCheckPlanRespVO.class);
    }

    @Override
    public CommonResult<DevicePeriodCheckPlanRespVO> savePlan(DevicePeriodCheckPlanSaveReqVO paramVO) {
        updateDevicePeriodCheckPlan(paramVO);

        //处理明细
        List<DevicePeriodCheckDO> devicePeriodCheckList = paramVO.getDevicePeriodCheckList();
        List<DevicePeriodCheckDO> detailList = devicePeriodCheckService.getListByPlanId(paramVO.getId());
        List<DevicePeriodCheckDO> updateList = new ArrayList<>();
        List<Long> deleteList = new ArrayList<>();
        List<DevicePeriodCheckDO> insertList = new ArrayList<>();
        for (DevicePeriodCheckDO dbDetail : detailList) {
            boolean findFlag = false;
            for(DevicePeriodCheckDO d : devicePeriodCheckList){
                if(dbDetail.getId().equals(d.getId())){
                    updateList.add(d);
                    findFlag = true;
                    break;
                }
            }
            if(!findFlag){
                deleteList.add(dbDetail.getId());
            }
        }
        for (DevicePeriodCheckDO d : devicePeriodCheckList) {
            boolean findFlag = false;
            for(DevicePeriodCheckDO dbDetail : detailList){
                if(d.getId().equals(dbDetail.getId())){
                    findFlag = true;
                    break;
                }
            }
            if(!findFlag){
                insertList.add(d);
            }
        }
        if(!updateList.isEmpty())
            devicePeriodCheckService.updateBatch(updateList);
        if(!deleteList.isEmpty())
            devicePeriodCheckService.deleteDevicePeriodCheckListByIds(deleteList);
        if(!insertList.isEmpty())
            devicePeriodCheckService.insertBatch(insertList);
        DevicePeriodCheckPlanDO entity = getDevicePeriodCheckPlan(paramVO.getId());
        DevicePeriodCheckPlanRespVO vo =  BeanUtils.toBean(entity, DevicePeriodCheckPlanRespVO.class);
        return CommonResult.success(vo);
    }

    @Override
    public CommonResult<DevicePeriodCheckPlanRespVO> submitApply(DevicePeriodCheckPlanSaveReqVO paramVO) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        //当前登录用户昵称
        String nickName = SecurityFrameworkUtils.getLoginUserNickname();
        Long id = paramVO.getId();
        DevicePeriodCheckPlanDO entity = getDevicePeriodCheckPlan(id);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String processDefKey = dictionaryBusinessService.getValueByDataKey(wfDicKey);
        if(ObjectUtils.isEmpty(processDefKey))
            throw exception0(DEVICE_PERIOD_CHECK_PLAN_NOT_EXISTS.getCode(), "请先配置流程定义");
        Map<String, Object> variables = new JSONObject();
        variables.put("mainId",  id);
        variables.put("applyUser",  nickName);
        variables.put("applyUserId",  loginUser.getId());
        variables.put("applyDepartment",  loginUser.getVisitDeptName());
        variables.put("applyDepartmentId",  loginUser.getVisitDeptId());
        variables.put("applyTime",  sdf.format(new Date()));
        variables.put(BPM_CALLBACK_BEAN_NAME, "devicePeriodCheckPlanService"); //流程回调时使用的service
        BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
        reqDTO.setBusinessKey(String.valueOf(id));
        reqDTO.setProcessDefinitionKey(processDefKey);
        reqDTO.setVariables(variables);
        CommonResult<String> result = bpmProcessInstanceApi.createProcessInstance(loginUser.getId(), reqDTO);
        if(!result.isSuccess()){
            throw exception0(DEVICE_PERIOD_CHECK_PLAN_NOT_EXISTS.getCode(), result.getMsg());
        }
        String wfInsId = result.getData();
        entity.setFlowInstanceId(wfInsId);
        entity.setFlowStatus(QmsCommonConstant.IN_PROGRESS);
        devicePeriodCheckPlanMapper.updateById(entity);
        DevicePeriodCheckPlanRespVO respVO = BeanUtils.toBean(entity, DevicePeriodCheckPlanRespVO.class);
        return CommonResult.success(respVO);
    }

    @Override
    public void updateDevicePeriodCheckPlan(DevicePeriodCheckPlanSaveReqVO updateReqVO) {
        // 校验存在
        validateDevicePeriodCheckPlanExists(updateReqVO.getId());
        // 更新
        DevicePeriodCheckPlanDO updateObj = BeanUtils.toBean(updateReqVO, DevicePeriodCheckPlanDO.class);
        devicePeriodCheckPlanMapper.updateById(updateObj);
    }

    @Override
    public void deleteDevicePeriodCheckPlan(Long id) {
        // 校验存在
        validateDevicePeriodCheckPlanExists(id);
        // 删除
        devicePeriodCheckPlanMapper.deleteById(id);
    }

    @Override
        public void deleteDevicePeriodCheckPlanListByIds(List<Long> ids) {
        // 校验存在
        validateDevicePeriodCheckPlanExists(ids);
        // 删除
        devicePeriodCheckPlanMapper.deleteByIds(ids);
        }

    private void validateDevicePeriodCheckPlanExists(List<Long> ids) {
        List<DevicePeriodCheckPlanDO> list = devicePeriodCheckPlanMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(DEVICE_PERIOD_CHECK_PLAN_NOT_EXISTS);
        }
    }

    private void validateDevicePeriodCheckPlanExists(Long id) {
        if (devicePeriodCheckPlanMapper.selectById(id) == null) {
            throw exception(DEVICE_PERIOD_CHECK_PLAN_NOT_EXISTS);
        }
    }

    @Override
    public DevicePeriodCheckPlanDO getDevicePeriodCheckPlan(Long id) {
        return devicePeriodCheckPlanMapper.selectById(id);
    }

    @Override
    public PageResult<DevicePeriodCheckPlanDO> getDevicePeriodCheckPlanPage(DevicePeriodCheckPlanPageReqVO pageReqVO) {
        return devicePeriodCheckPlanMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<JSONObject> callback(QmsBpmDTO reqDTO) {
        log.error("流程回调：{}", JSONObject.toJSONString(reqDTO));
        JSONObject variables = reqDTO.getVariables();
        JSONObject taskVariables = variables.getJSONObject("taskVariables");
        String processInsId = variables.getString(QmsBpmConstant.BPM_PROCESS_INS_ID);
        String currentActivityInsId = variables.getString(QmsBpmConstant.BPM_CUR_ACTIVITY_INS_ID);
        String currentActivityId = variables.getString(QmsBpmConstant.BPM_CALLBACK_ACTIVITY_ID);
        String currentActivityName = variables.getString(QmsBpmConstant.BPM_CALLBACK_ACTIVITY_NAME);
        String returnFlag = variables.getString(QmsBpmConstant.BPM_REJECT_TO_FIRST_FLAG); //退回标识。在任务监听中设置
        //同一个节点实例只触发一次
        String checkKey = currentActivityInsId;
        if(ObjectUtils.isEmpty(currentActivityInsId))
            checkKey = processInsId + "-create";
        if("1".equals(returnFlag))
            checkKey += "-reject";
        try{
            dataKeyCheckService.create(checkKey, this.getClass().getName());
        }catch (Exception e){
//            e.printStackTrace();
            log.error("checkKey 重复：key={}", checkKey);
            return CommonResult.success(new JSONObject());
        }
        //流程状态  1-提交（含退回）  4-取消流程
        String PROCESS_STATUS = variables.getString(QmsBpmConstant.PROCESS_INSTANCE_VARIABLE_STATUS);
        String mainId = variables.getString("mainId");
        JSONArray fieldExtensions = new JSONArray();
        if(variables.containsKey(QmsBpmConstant.BPM_FIELD_EXTENSIONS)){
            fieldExtensions = variables.getJSONArray(QmsBpmConstant.BPM_FIELD_EXTENSIONS);
        }
        DevicePeriodCheckPlanDO entity = getDevicePeriodCheckPlan(Long.valueOf(mainId));

        //判断是否最后一个节点
        String lastActivityFlag = "0";
        String firstActivityFlag = "0";
        if(!fieldExtensions.isEmpty()){
            for(int i = 0; i < fieldExtensions.size(); i++){
                JSONObject fieldExtension = fieldExtensions.getJSONObject(i);
                String stringValue = fieldExtension.getString("stringValue");
                if(fieldExtension.getString("fieldName").equalsIgnoreCase(QmsBpmConstant.BPM_LAST_ACTIVITY_FLAG) && "1".equals(stringValue)){
                    lastActivityFlag = "1";
                }
                if(fieldExtension.getString("fieldName").equalsIgnoreCase(QmsBpmConstant.BPM_FIRST_ACTIVITY_FLAG) && "1".equals(stringValue)){
                    firstActivityFlag = "1";
                }
            }
        }
        //"RETURN_FLAG_Activity_001": true 标识驳回到发起环节
        if(("1").equals(returnFlag)){
            //驳回。流程需要配置退回到发起节点
            entity.setFlowStatus(QmsCommonConstant.REJECTED);
            dataOpinionService.disableOpinionsByBusId(entity.getId());
        }else if("4".equals(PROCESS_STATUS)){
            //作废
            entity.setFlowStatus(QmsCommonConstant.VOID);
            devicePeriodCheckService.updateEffectiveFlag(entity.getId(), "0");
        }else if("1".equals(PROCESS_STATUS)){
            //通过
//            assembleSignature(currentActivityId, entity);
            DataCommonType dataCommonType = new DataCommonType();
            dataCommonType.setBusinessId(entity.getId());
            dataCommonType.setFlowInstanceId(entity.getFlowInstanceId());
            dataOpinionService.saveOpinionByWfCallback(dataCommonType, currentActivityId, currentActivityName, taskVariables);
            if("1".equals(firstActivityFlag))
                entity.setFlowStatus(QmsCommonConstant.IN_PROGRESS);    //驳回后重新提交
            if("1".equals(lastActivityFlag)){
                entity.setFlowStatus(QmsCommonConstant.COMPLETED);      //结束审批
            }
            devicePeriodCheckService.updateEffectiveFlag(entity.getId(), "1");
        }
        devicePeriodCheckPlanMapper.updateById(entity);
        JSONObject ret = new JSONObject();
        return CommonResult.success(ret);
    }
}