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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
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.DataCollectionDO;
import com.zt.plat.module.qms.common.data.dal.dataobject.DataCommonType;
import com.zt.plat.module.qms.common.data.dal.dataobject.DataOpinionDO;
import com.zt.plat.module.qms.common.data.dal.dataobject.DataTemplateDO;
import com.zt.plat.module.qms.common.data.service.DataCollectionService;
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.enums.QmsBpmConstant;
import com.zt.plat.module.qms.enums.QmsCommonConstant;
import com.zt.plat.module.qms.resource.device.controller.vo.DeviceApplyDetailPageReqVO;
import com.zt.plat.module.qms.resource.device.controller.vo.DeviceApplyPageReqVO;
import com.zt.plat.module.qms.resource.device.controller.vo.DeviceApplyRespVO;
import com.zt.plat.module.qms.resource.device.controller.vo.DeviceApplySaveReqVO;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceApplyDetailDO;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceConfigFlowDO;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceInfomationDO;
import com.zt.plat.module.qms.resource.device.enums.DeviceBizEnum;
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.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceApplyDO;
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.DeviceApplyMapper;

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

/**
 * 设备通用流程,验收、降级、停用、报废、还原、启用 Service 实现类
 *
 * @author 后台管理-1
 */
@Validated
@Slf4j
@Service("deviceApplyService")
public class DeviceApplyServiceImpl implements DeviceApplyService, BMPCallbackInterface {

    @Resource private DeviceApplyMapper deviceApplyMapper;
    @Resource private DeviceConfigFlowService deviceConfigFlowService;
    @Resource private DeviceInfomationService deviceInfomationService;
    @Resource private DeviceApplyDetailService deviceApplyDetailService;
    @Resource private DataCollectionService dataCollectionService;
    @Resource private DataTemplateService dataTemplateService;
    @Resource private BpmProcessInstanceApi bpmProcessInstanceApi;
    @Resource private DataKeyCheckService dataKeyCheckService;
    @Resource private DataOpinionService dataOpinionService;
    private final String titleKey = "title";
    private final String borrowConfirmKey = "borrowConfirm";

    @Override
    public DeviceApplyRespVO createDeviceApply(DeviceApplySaveReqVO createReqVO) {
        // 插入
        DeviceApplyDO deviceApply = BeanUtils.toBean(createReqVO, DeviceApplyDO.class);
        deviceApplyMapper.insert(deviceApply);
        // 返回
        return BeanUtils.toBean(deviceApply, DeviceApplyRespVO.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<DeviceApplyRespVO> createTempData(DeviceApplySaveReqVO createReqVO) {
        String businessType = createReqVO.getBusinessCode();
        if(ObjectUtils.isEmpty(businessType))
            return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "请选择业务类型");
        DeviceConfigFlowDO config = deviceConfigFlowService.getByBusinessType(businessType);
        if(ObjectUtils.isEmpty(config))
            return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "业务类型配置不存在（"+businessType+"），请联系管理员处理");
//        DeviceBizEnum deviceBizEnum = DeviceBizEnum.getByCode(businessType);
        DeviceApplyDO deviceApply = BeanUtils.toBean(createReqVO, DeviceApplyDO.class);
        if(!ObjectUtils.isEmpty(config.getTemplateKey())){
            DataTemplateDO dataTemplate = dataTemplateService.getLatestDataByKey(config.getTemplateKey());
            if(ObjectUtils.isEmpty(dataTemplate))
                return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "表单编辑器模板不存在（"+config.getTemplateKey()+"），请联系管理员处理");
            deviceApply.setTemplateId(dataTemplate.getId());
        }
        DataCollectionDO dataCollection = dataCollectionService.getLatestDataCollectionByKey(config.getDataCollectionKey());
        if(ObjectUtils.isEmpty(dataCollection))
            return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "数据集不存在（"+config.getDataCollectionKey()+"），请联系管理员处理");
        deviceApply.setBusinessName(config.getBusinessName());
        deviceApply.setDataCollectionId(dataCollection.getId());
        //取当前用户
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        String nickName = SecurityFrameworkUtils.getLoginUserNickname();
        deviceApply.setApplyUser(loginUser.getId());
        deviceApply.setApplyUserName(nickName);
        deviceApply.setApplyDepartment(loginUser.getVisitDeptId());
        deviceApply.setApplyDepartmentName(loginUser.getVisitDeptName());
        deviceApply.setBusinessStatus(QmsCommonConstant.TEMP_DATA_CODE);
        //生成标题
        String title = nickName + "的" + config.getBusinessName() + "申请_" + new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss").format(new Date());
        JSONObject formData = new JSONObject();
        formData.put(titleKey, title);
        deviceApply.setFormData(formData.toJSONString());
        deviceApply.setTitle( title);
        deviceApplyMapper.insert(deviceApply);
        // 返回
        return CommonResult.success(BeanUtils.toBean(deviceApply, DeviceApplyRespVO.class));
    }


    //增加明细
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<Boolean> addDetail(JSONObject param) {
        String deviceIds = param.getString("deviceIds");
        String applyId = param.getString("applyId");
        if(ObjectUtils.isEmpty(deviceIds))
            return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "请选择设备");
        if(ObjectUtils.isEmpty(applyId))
            return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "缺少申请id参数，请刷新后重试！");
        List<DeviceInfomationDO> deviceList = deviceInfomationService.getListByIds(deviceIds);
        if(deviceList.isEmpty())
            return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "设备不存在");
        Long id = Long.valueOf(applyId);
        DeviceApplyDO apply = getDeviceApply(id);
        List<Long> deviceInfoIdList = new ArrayList<>();
        for (DeviceInfomationDO device : deviceList) {
            deviceInfoIdList.add(device.getId());
        }
        //查询已有明细，避免重复添加
        DeviceApplyDetailPageReqVO detailPageReqVO = new DeviceApplyDetailPageReqVO();
        detailPageReqVO.setApplyId(id);
        detailPageReqVO.setDeviceInfoIdList(deviceInfoIdList);
        List<DeviceApplyDetailDO> detailList = deviceApplyDetailService.selectList(detailPageReqVO);
        //过滤已添加设备
        List<DeviceInfomationDO> addDeviceList = deviceList.stream().filter(device ->
                detailList.stream().noneMatch(detail -> detail.getDeviceInfomationId().equals(device.getId()))).toList();
        List<DeviceApplyDetailDO> detailDOList = new ArrayList<>();
        for (DeviceInfomationDO device : addDeviceList) {
            DeviceApplyDetailDO detail = new DeviceApplyDetailDO();
            detail.setApplyId(id);
            detail.setDeviceInfomationId(device.getId());
            detailDOList.add(detail);
        }
        deviceApplyDetailService.insertBatch(detailDOList);

        //更新设备状态
//        List<DeviceInfomationDO> deviceUpdateList = new ArrayList<>();
//        //添加明细后，修改对应业务状态为running
//        for (DeviceInfomationDO device : addDeviceList) {
//            CommonResult<DeviceInfomationDO> deviceUpdateRet = deviceInfomationService.initDeviceStatusByBizType(device, apply.getBusinessCode(), QmsCommonConstant.RUNNING, false);
//            deviceUpdateList.add(deviceUpdateRet.getData());
//        }
//        if(!deviceUpdateList.isEmpty())
//            deviceInfomationService.updateBatch(deviceUpdateList);

        return CommonResult.success(true);
    }

    @Override
    public CommonResult<Boolean> removeDetail(JSONObject param) {

        String detailIds = param.getString("detailIds");
        if(ObjectUtils.isEmpty(detailIds))
            return CommonResult.error(DEVICE_APPLY_NOT_EXISTS.getCode(), "请选择需要删除的明细数据");
        List<Long> detailIdList = Arrays.stream(detailIds.split(",")).map(Long::valueOf).toList();
        deviceApplyDetailService.deleteDeviceApplyDetailListByIds(detailIdList);
        return CommonResult.success(true);
    }

    //保存
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<Boolean> saveDeviceApply(DeviceApplySaveReqVO updateReqVO) {

        // 校验存在
        DeviceApplyDO backData = getDeviceApply(updateReqVO.getId());
        if(backData == null)
            throw exception(DEVICE_APPLY_NOT_EXISTS);
        if(QmsCommonConstant.TEMP_DATA_CODE.equals(backData.getBusinessStatus())){
            updateReqVO.setBusinessStatus(QmsCommonConstant.NOT_START);
        }
        //处理动态表单字段
        String formData = updateReqVO.getFormData();
        if(!ObjectUtils.isEmpty(formData)) {
            assembleFormData(formData, updateReqVO);
        }
        // 更新
        DeviceApplyDO updateObj = BeanUtils.toBean(updateReqVO, DeviceApplyDO.class);
        deviceApplyMapper.updateById(updateObj);
        return CommonResult.success(true);
    }

    private void assembleFormData(String formData, DeviceApplySaveReqVO updateReqVO){
        JSONObject jsonObject = JSONObject.parseObject(formData);
        DeviceApplySaveReqVO jsonVo = jsonObject.toJavaObject(DeviceApplySaveReqVO.class);
        CopyOptions copyOptions = CopyOptions.create();
        copyOptions.setIgnoreNullValue(true);
        BeanUtil.copyProperties(jsonVo, updateReqVO, copyOptions);
    }

    //提交申请-发起流程
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<DeviceApplyRespVO> submitDeviceApply(DeviceApplySaveReqVO param) {
        LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
        //当前登录用户昵称
        String nickName = SecurityFrameworkUtils.getLoginUserNickname();
        Long id = param.getId();
        DeviceApplyDO entity = getDeviceApply(id);
        JSONObject formData = new JSONObject();
        if(entity.getFormData() != null)
            formData = JSONObject.parseObject(entity.getFormData());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String businessCode = entity.getBusinessCode();
        DeviceConfigFlowDO flow = deviceConfigFlowService.getByBusinessType(businessCode);

        formData.put("mainId",  id);
        formData.put("applyUser",  nickName);
        formData.put("applyUserId",  loginUser.getId());
        formData.put("applyDepartment",  loginUser.getVisitDeptName());
        formData.put("applyDepartmentId",  loginUser.getVisitDeptId());
        formData.put("applyTime",  sdf.format(new Date()));
        Map<String, Object> variables = formData.toJavaObject(Map.class);
        variables.put(BPM_CALLBACK_BEAN_NAME, "deviceApplyService"); //流程回调时使用的service
        BpmProcessInstanceCreateReqDTO reqDTO = new BpmProcessInstanceCreateReqDTO();
        reqDTO.setBusinessKey(String.valueOf(id));
        reqDTO.setProcessDefinitionKey(flow.getFlowKey());
        reqDTO.setVariables(variables);
        CommonResult<String> result = bpmProcessInstanceApi.createProcessInstance(loginUser.getId(), reqDTO);
        if(!result.isSuccess()){
            throw exception0(ERROR_CODE_MODULE_COMMON, result.getMsg());
        }
        String wfInsId = result.getData();
        entity.setFlowInstanceId(wfInsId);
        entity.setBusinessStatus(QmsCommonConstant.IN_PROGRESS);
        deviceApplyMapper.updateById(entity);
        DeviceApplyRespVO respVO = BeanUtils.toBean(entity, DeviceApplyRespVO.class);

        //设备维修流程，修改设备状态为维修中
        if(DeviceBizEnum.repair.getCode().equals(businessCode)){
            updateDeviceStateByApply(entity, DeviceBizEnum.switchOn);
        }

        return CommonResult.success(respVO);
    }

    @Override
    public void updateDeviceApply(DeviceApplySaveReqVO updateReqVO) {
        // 校验存在
        validateDeviceApplyExists(updateReqVO.getId());
        // 更新
        DeviceApplyDO updateObj = BeanUtils.toBean(updateReqVO, DeviceApplyDO.class);
        deviceApplyMapper.updateById(updateObj);
    }

    @Override
    public void deleteDeviceApply(Long id) {
        // 校验存在
        validateDeviceApplyExists(id);
        // 删除
        deviceApplyMapper.deleteById(id);
    }

    @Override
    public void deleteDeviceApplyListByIds(List<Long> ids) {
        // 校验存在
        validateDeviceApplyExists(ids);
        // 删除
        deviceApplyMapper.deleteByIds(ids);
    }

    private void validateDeviceApplyExists(List<Long> ids) {
        List<DeviceApplyDO> list = deviceApplyMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(DEVICE_APPLY_NOT_EXISTS);
        }
    }

    private void validateDeviceApplyExists(Long id) {
        if (deviceApplyMapper.selectById(id) == null) {
            throw exception(DEVICE_APPLY_NOT_EXISTS);
        }
    }

    @Override
    public DeviceApplyDO getDeviceApply(Long id) {
        return deviceApplyMapper.selectById(id);
    }

    @Override
    public CommonResult<JSONObject> getWithOpinions(Long id) {
        DeviceApplyDO entity = deviceApplyMapper.selectById(id);
        List<DataOpinionDO> opinions = dataOpinionService.getListByBusId(entity.getId());
        JSONObject opinionJson = new JSONObject();
        for(DataOpinionDO opinion : opinions){
            String nodeKey = opinion.getNodeKey();
            if(ObjectUtils.isEmpty(nodeKey))
                continue;
            JSONObject nodeJson = new JSONObject();
            LocalDateTime opinionTime = opinion.getOpinionTime();
            nodeJson.put("nodeName", opinion.getNodeName());
            nodeJson.put("nodeKey", opinion.getNodeKey());
            nodeJson.put("opinionContent", opinion.getOpinionContent());
            //opinionTime转年月日
            if(opinionTime != null)
                nodeJson.put("opinionTime", opinionTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            nodeJson.put("opinionUserName", opinion.getOpinionUserName());
            nodeJson.put("opinionUserId", opinion.getOpinionUserId());
            nodeJson.put("opinionDepartmentName", opinion.getOpinionDepartmentName());
            nodeJson.put("opinionDepartmentId", opinion.getOpinionDepartmentId());
            nodeJson.put("opinionSignatureId", opinion.getOpinionSignatureId());
            opinionJson.put(nodeKey, nodeJson);
        }
        //entity转json
        JSONObject json = JSONObject.parseObject(JSONObject.toJSONString(entity));
        String formData = json.getString("formData");
        if(!ObjectUtils.isEmpty(formData)){
            try{
                JSONObject formDataJson = JSONObject.parseObject(formData);
                json.put("formData", formDataJson);
            }catch (Exception e){
                log.error("设备维修流程数据转换异常：{}", e.getMessage());
                log.error("异常字符串：{}", formData);
                e.printStackTrace();

            }
        }
        json.put("opinions", opinionJson);
        return CommonResult.success(json);
    }

    @Override
    public PageResult<DeviceApplyDO> getDeviceApplyPage(DeviceApplyPageReqVO pageReqVO) {
        return deviceApplyMapper.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);
        }
        DeviceApplyDO entity = getDeviceApply(Long.valueOf(mainId));

        //判断是否最后一个节点
        String lastActivityFlag = "0";
        String firstActivityFlag = "0";
        String borrowConfirm = "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";
                }
                if(fieldExtension.getString("fieldName").equalsIgnoreCase(borrowConfirmKey) && "1".equals(stringValue)){
                    borrowConfirm = "1";
                }
            }
        }
        //"RETURN_FLAG_Activity_001": true 标识驳回到发起环节
        if(("1").equals(returnFlag)){
            //驳回。流程需要配置退回到发起节点
            entity.setBusinessStatus(QmsCommonConstant.REJECTED);
            dataOpinionService.disableOpinionsByBusId(entity.getId());
        }else if("4".equals(PROCESS_STATUS)){
            //作废
            entity.setBusinessStatus(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.setBusinessStatus(QmsCommonConstant.IN_PROGRESS);    //驳回后重新提交
            if("1".equals(lastActivityFlag)){
                entity.setBusinessStatus(QmsCommonConstant.COMPLETED);      //结束审批
                //更新设备状态
                updateDeviceStateByApply(entity, DeviceBizEnum.switchOff);
            }
            if("1".equals(borrowConfirm)){
                //更新设备状态
                updateDeviceStateByApply(entity, DeviceBizEnum.switchOn);
            }
        }
        deviceApplyMapper.updateById(entity);
        JSONObject ret = new JSONObject();
        return CommonResult.success(ret);
    }

    /*
    * 修改设备状态
    * switchState: 切换状态（switchOn（1）： 切换为开， switchOff（0）：切换为关。 按bizType判断要更新的字段。按bizType语义判断更新的值。）
    * */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateDeviceStateByApply(DeviceApplyDO entity, Integer switchState){
        List<DeviceInfomationDO> deviceList = new ArrayList<>();
        List<DeviceApplyDetailDO> detailList = deviceApplyDetailService.selectListByApplyId(entity.getId());
        String bizType = entity.getBusinessCode();
//        String flag = json.getString("flag");
//        boolean updateStateShow = json.getBoolean("updateStateShow");
        for(DeviceApplyDetailDO detail : detailList){
            DeviceInfomationDO device = deviceInfomationService.getDeviceInfomation(detail.getDeviceInfomationId());
            device = deviceInfomationService.initDeviceStatusByBizType(device, bizType, switchState).getData();
            deviceList.add(device);
        }
        deviceInfomationService.updateBatch(deviceList);
    }

}