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.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.dal.dataobject.DataTemplateDO;
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.data.service.DataTemplateService;
import com.zt.plat.module.qms.common.dic.service.DictionaryBusinessService;
import com.zt.plat.module.qms.common.service.BusinessFileService;
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.common.DeviceUtil;
import com.zt.plat.module.qms.resource.device.controller.vo.*;
import com.zt.plat.module.qms.resource.device.dal.dataobject.*;
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.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
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.DeviceCalibrationMapper;

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_CALIBRATION_NOT_EXISTS;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.DEVICE_CALIBRATION_PLAN_NOT_EXISTS;
import static com.zt.plat.module.qms.enums.QmsBpmConstant.BPM_CALLBACK_BEAN_NAME;

/**
 * 设备-检定校准 Service 实现类
 *
 * @author 后台管理-1
 */
@Service("deviceCalibrationService")
@Validated
@Slf4j
public class DeviceCalibrationServiceImpl implements DeviceCalibrationService, BMPCallbackInterface {

    @Resource private DeviceCalibrationMapper deviceCalibrationMapper;
    @Resource private DeviceInfomationService deviceInfomationService;
    @Resource private DictionaryBusinessService dictionaryBusinessService;
    @Resource private BpmProcessInstanceApi bpmProcessInstanceApi;
    @Resource private DataKeyCheckService dataKeyCheckService;
    @Resource private DataOpinionService dataOpinionService;
    @Resource private DataTemplateService dataTemplateService;
    @Resource private BusinessFileService businessFileService;
    private final String wfDicKey = "DeviceCalibrationWfKey";
    private final String formDicKey = "DeviceCalibrationFormKey";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createListByPlan(DeviceCalibrationPlanDO plan) {
        Long planId = plan.getId();
        String checkYear = plan.getCheckYear();
        JSONObject ruleParam = new JSONObject();
        ruleParam.put("businessType", DeviceConstant.CALIBRATION_TYPE);
        List<DeviceCalibrationDO> checkList = new ArrayList<>();
        String wfStatus = QmsCommonConstant.COMPLETED;
        //处理设备
        List<DeviceInfoWithBizConfigVO> deviceList = deviceInfomationService.getListNeedByRule(ruleParam);
        if(deviceList.isEmpty())
            throw exception0(DEVICE_CALIBRATION_NOT_EXISTS.getCode(), "没有需要创建检定校准计划的设备，请检查“设备业务配置”！");
        List<Long> deviceIds = convertList(deviceList, DeviceInfoWithBizConfigVO::getId);
        List<DeviceCalibrationVO> lastDeviceDataList = getLastDataCheckList(deviceIds, wfStatus).getData();
        String formKey = dictionaryBusinessService.getValueByDataKey(formDicKey);
        DataTemplateDO formTemplate = dataTemplateService.getLatestDataByKey(formKey);
        Long formTemplateId = formTemplate.getId();
        for (DeviceInfoWithBizConfigVO device : deviceList) {
            DeviceConfigBusinessRuleDO rule = device.getRule();
            Long deviceId = device.getId();
            initCalibrationData(planId, checkList, lastDeviceDataList, rule, deviceId, formTemplateId);
        }
        if(checkList.isEmpty())
            throw exception0(DEVICE_CALIBRATION_NOT_EXISTS.getCode(), "没有需要创建检定校准计划的设备！");
        deviceCalibrationMapper.insertBatch(checkList);
    }

    private void initCalibrationData(Long planId, List<DeviceCalibrationDO> checkList, List<DeviceCalibrationVO> lastCheckList, DeviceConfigBusinessRuleDO rule, Long deviceId, Long formTemplateId) {
        DeviceCalibrationDO data = new DeviceCalibrationDO();
        DeviceCalibrationVO lastData = null;
        for(DeviceCalibrationVO lastDO : lastCheckList){
            if(lastDO.getDeviceId().equals(deviceId)){
                lastData = lastDO;
                break;
            }
        }
        //计算下一次执行日期
        LocalDateTime nextDate = null;
        if(lastData != null){
            data.setLastCheckDate(lastData.getCheckDate());
            LocalDateTime lastDate = lastData.getCheckDate();
            LocalDateTime[] dateRange = DeviceUtil.getDateRangeByFrequency(lastDate, true, rule.getFrequencyType(), rule.getFrequency());
            if(dateRange != null){
                nextDate = dateRange[0];
            }
        }
        //todo 过滤当前年度已执行过期间核查的数据
        data.setPlanId(planId);
        data.setDeviceId(deviceId);
        data.setPlanCheckDate(nextDate);
        data.setSpecification(rule.getStandard());
        data.setCheckType(rule.getCalibrationCheckType());
        data.setFrequencyRemark(rule.getFrequencyRemark());
        data.setFlowStatus(QmsCommonConstant.NOT_START);
        data.setFormId(formTemplateId);
        checkList.add(data);
    }

    @Override
    public CommonResult<List<DeviceCalibrationVO>> getLastDataCheckList(List<Long> deviceIds, String flowStatus) {
        JSONObject param = new JSONObject();
        param.put("deviceIds", deviceIds);
        param.put("flowStatus", flowStatus);
        List<DeviceCalibrationVO> list = deviceCalibrationMapper.getLastDataCheckList(param);
        return CommonResult.success(list);
    }

    @Override
    public IPage<DeviceCalibrationVO> queryPageList(Page<DeviceCalibrationPageReqVO> page, DeviceCalibrationPageReqVO pageReqVO) {
        return deviceCalibrationMapper.queryPageList(page, pageReqVO);
    }

    @Override
    public void updateEffectiveFlag(Long planId, String effectiveFlag) {
        LambdaUpdateWrapper<DeviceCalibrationDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(DeviceCalibrationDO::getPlanId, planId);
        updateWrapper.set(DeviceCalibrationDO::getEffectiveFlag, effectiveFlag);
        deviceCalibrationMapper.update(updateWrapper);
    }

    @Override
    public List<DeviceCalibrationDO> getListByPlanId(Long planId) {
        LambdaQueryWrapper<DeviceCalibrationDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeviceCalibrationDO::getPlanId, planId);
        return deviceCalibrationMapper.selectList(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<DeviceCalibrationRespVO> submitApply(DeviceCalibrationSaveReqVO paramVO) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        //当前登录用户昵称
        String nickName = SecurityFrameworkUtils.getLoginUserNickname();
        Long id = paramVO.getId();
        DeviceCalibrationDO entity = getDeviceCalibration(id);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String processDefKey = dictionaryBusinessService.getValueByDataKey(wfDicKey);
        if(ObjectUtils.isEmpty(processDefKey))
            throw exception0(DEVICE_CALIBRATION_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, "deviceCalibrationService"); //流程回调时使用的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_CALIBRATION_PLAN_NOT_EXISTS.getCode(), result.getMsg());
        }
        String wfInsId = result.getData();
        entity.setFlowInstanceId(wfInsId);
        entity.setFlowStatus(QmsCommonConstant.IN_PROGRESS);
        deviceCalibrationMapper.updateById(entity);
        DeviceCalibrationRespVO respVO = BeanUtils.toBean(entity, DeviceCalibrationRespVO.class);
        return CommonResult.success(respVO);
    }

    @Override
    public DeviceCalibrationRespVO createDeviceCalibration(DeviceCalibrationSaveReqVO createReqVO) {
        // 插入
        DeviceCalibrationDO deviceCalibration = BeanUtils.toBean(createReqVO, DeviceCalibrationDO.class);
        deviceCalibrationMapper.insert(deviceCalibration);
        // 返回
        return BeanUtils.toBean(deviceCalibration, DeviceCalibrationRespVO.class);
    }

    @Override
    public DeviceCalibrationRespVO createByDeviceId(DeviceCalibrationSaveReqVO createReqVO) {
        Long deviceId = createReqVO.getDeviceId();
        if(deviceId == null)
            throw exception0(DEVICE_CALIBRATION_NOT_EXISTS.getCode(), "请选择设备");
        //查询设备大类、检定校准配置信息
        JSONObject ruleParam = new JSONObject();
        ruleParam.put("businessType", DeviceConstant.CALIBRATION_TYPE);
        ruleParam.put("deviceId", deviceId);
        List<DeviceInfoWithBizConfigVO> deviceList = deviceInfomationService.getListNeedByRule(ruleParam);
        if(deviceList.isEmpty()){
            throw exception0(DEVICE_CALIBRATION_NOT_EXISTS.getCode(), "当前设备未配置检定校准规则，请配置后再操作");
        }
        DeviceInfoWithBizConfigVO configVO = deviceList.get(0);
        DeviceConfigBusinessRuleDO rule = configVO.getRule();
        if(rule == null){
            throw exception0(DEVICE_CALIBRATION_NOT_EXISTS.getCode(), "当前设备未配置检定校准规则，请配置后再操作");
        }
        String formKey = dictionaryBusinessService.getValueByDataKey(formDicKey);
        DataTemplateDO formTemplate = dataTemplateService.getLatestDataByKey(formKey);
        Long formTemplateId = formTemplate.getId();
        DeviceCalibrationDO entity = new DeviceCalibrationDO();
        entity.setDeviceId(deviceId);
        entity.setPlanId(0L);
        entity.setEffectiveFlag("1");
        entity.setFormId(formTemplateId);
        entity.setFlowStatus(QmsCommonConstant.NOT_START);


        entity.setSpecification(rule.getStandard());
        entity.setCheckType(rule.getCalibrationCheckType());
        entity.setFrequencyRemark(rule.getFrequencyRemark());
        deviceCalibrationMapper.insert(entity);
        return BeanUtils.toBean(entity, DeviceCalibrationRespVO.class);
    }

    @Override
    @Transactional
    public DeviceCalibrationDO updateDeviceCalibration(DeviceCalibrationSaveReqVO updateReqVO) {
        // 校验存在
        validateDeviceCalibrationExists(updateReqVO.getId());
        // 更新
        DeviceCalibrationDO updateObj = BeanUtils.toBean(updateReqVO, DeviceCalibrationDO.class);
        deviceCalibrationMapper.updateById(updateObj);
        businessFileService.deleteBusinessFileList(updateReqVO.getDeleteFileIdList());
        return updateObj;
    }

    @Override
    public void deleteDeviceCalibration(Long id) {
        // 校验存在
        validateDeviceCalibrationExists(id);
        // 删除
        deviceCalibrationMapper.deleteById(id);
    }

    @Override
        public void deleteDeviceCalibrationListByIds(List<Long> ids) {
        // 校验存在
        validateDeviceCalibrationExists(ids);
        // 删除
        deviceCalibrationMapper.deleteByIds(ids);
        }

    private void validateDeviceCalibrationExists(List<Long> ids) {
        List<DeviceCalibrationDO> list = deviceCalibrationMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(DEVICE_CALIBRATION_NOT_EXISTS);
        }
    }

    private void validateDeviceCalibrationExists(Long id) {
        if (deviceCalibrationMapper.selectById(id) == null) {
            throw exception(DEVICE_CALIBRATION_NOT_EXISTS);
        }
    }

    @Override
    public DeviceCalibrationDO getDeviceCalibration(Long id) {
        return deviceCalibrationMapper.selectById(id);
    }

    @Override
    public DeviceCalibrationVO getDeviceCalibrationVO(Long id) {
        Page<DeviceCalibrationPageReqVO> page = new Page<>(1,10);
        DeviceCalibrationPageReqVO param = new DeviceCalibrationPageReqVO();
        param.setId( id);
        IPage<DeviceCalibrationVO> pageList = queryPageList(page, param);
        PageResult<DeviceCalibrationVO> pageResult = new PageResult<>(pageList.getRecords(), pageList.getTotal());
        if(pageResult.getList().isEmpty())
            return null;
        DeviceCalibrationVO vo = pageResult.getList().get(0);
        //处理审批意见
        JSONObject opinion = dataOpinionService.assembleOpinion(id);
        vo.setSignatureData( opinion);
        return vo;
    }

    @Override
    public PageResult<DeviceCalibrationDO> getDeviceCalibrationPage(DeviceCalibrationPageReqVO pageReqVO) {
        return deviceCalibrationMapper.selectPage(pageReqVO);
    }

    @Override
    public void updateBatch(List<DeviceCalibrationDO> list) {
        deviceCalibrationMapper.updateBatch(list);
    }

    @Override
    public void insertBatch(List<DeviceCalibrationDO> list) {
        deviceCalibrationMapper.insertBatch(list);
    }

    @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);
        }
        DeviceCalibrationDO entity = getDeviceCalibration(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);
        }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);      //结束审批
            }
        }
        deviceCalibrationMapper.updateById(entity);
        JSONObject ret = new JSONObject();
        return CommonResult.success(ret);
    }

    @Override
    public DeviceCalibrationVO getLastData(JSONObject param) {
        return deviceCalibrationMapper.getLastData(param);
    }
}