package cn.iocoder.yudao.module.pms.service.failure;

import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.pms.constant.PmsConstants;
import cn.iocoder.yudao.module.pms.controller.admin.failure.vo.IotFailureReportPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.failure.vo.IotFailureReportProcessVO;
import cn.iocoder.yudao.module.pms.controller.admin.failure.vo.IotFailureReportSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonRelationSaveReqVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.failure.IotFailureReportDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdeviceperson.IotDevicePersonDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.maintain.IotMaintainDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.failure.IotFailureReportMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.maintain.IotMaintainMapper;
import cn.iocoder.yudao.module.pms.enums.common.FailureAuditStatusEnum;
import cn.iocoder.yudao.module.pms.message.PmsMessage;
import cn.iocoder.yudao.module.pms.service.IotDeviceService;
import cn.iocoder.yudao.module.pms.service.iotdeviceperson.IotDevicePersonService;
import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO;
import cn.iocoder.yudao.module.system.api.dingtalk.DingtalkSendApi;
import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
import cn.iocoder.yudao.module.system.api.permission.RoleApi;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import com.google.common.collect.ImmutableList;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_FAILURE_REPORT_NOT_EXISTS;

/**
 * 故障上报 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class IotFailureReportServiceImpl implements IotFailureReportService {
    public static final String PROCESS_KEY = "failure-report";
    public static final String RH_PROCESS_KEY = "rh-failure-report";
    @Resource
    private IotFailureReportMapper iotFailureReportMapper;
    @Resource
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private NotifyMessageSendApi notifyMessageSendApi;
    @Resource
    private DeptService deptService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource
    private DingtalkSendApi dingtalkSendApi;
    @Resource
    private BpmProcessInstanceApi processInstanceApi;
    @Autowired
    private IotMaintainMapper iotMaintainMapper;
    @Autowired
    private DeptApi deptApi;
    @Autowired
    private RoleApi roleApi;
    @Autowired
    private PmsMessage pmsMessage;
    @Autowired
    private IotDevicePersonService iotDevicePersonService;
    @Autowired
    private IotDeviceService iotDeviceService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void approvalFailureReport(Long id, Integer bpmResult) {
        IotFailureReportDO failureReportDO = iotFailureReportMapper.selectById(id);
        if (Objects.nonNull(failureReportDO.getAssigneeUserId())) {
            if(bpmResult ==2 ){
                //更新故障上报状态及审核状态
                failureReportDO.setStatus("trans");//转工单
                failureReportDO.setAuditStatus(FailureAuditStatusEnum.APPROVE.getStatus());
                iotFailureReportMapper.insertOrUpdate(failureReportDO);
                //生成工单
                IotMaintainDO iotMaintainDO = new IotMaintainDO();
                BeanUtils.copyProperties(failureReportDO, iotMaintainDO);
                //判断是否是瑞恒，如果是瑞恒的话先更新状态为维修人员填写
                String deviceCompany = iotDeviceService.getDeviceCompany(failureReportDO.getDeviceId());
                if ("rh".equals(deviceCompany)) {
                    iotMaintainDO.setStatus("personnel");
                    iotMaintainDO.setType("");
                } else {
                    iotMaintainDO.setStatus("tx");
                }
                iotMaintainDO.setPic(null);
                //iotMaintainDO.setAuditStatus(0);
                iotMaintainDO.setAuditStatus(null);
                iotMaintainDO.setMaintainType("故障上报");
                iotMaintainDO.setMaintainPerson(Objects.isNull(failureReportDO.getAssigneeUserId())? Long.valueOf(failureReportDO.getCreator()) :failureReportDO.getAssigneeUserId());
                AdminUserRespDTO apiUser = adminUserApi.getUser(iotMaintainDO.getMaintainPerson());
                if (Objects.isNull(apiUser)) {
                    throw new ServiceException(new ErrorCode(11,"责任人不存在"));
                }
                iotMaintainDO.setMaintainPersonName(apiUser.getNickname());
                iotMaintainDO.setFailureId(failureReportDO.getId());
                iotMaintainDO.setId(null);
                iotMaintainDO.setOutFile("[]");
                iotMaintainMapper.insert(iotMaintainDO);
                //发送消息
                Map<String, Object> templateParams = new HashMap<>();
                templateParams.put("name", iotMaintainDO.getDeviceName());
                templateParams.put("businessType", PmsConstants.GENERATE_MAINTAIN);
                templateParams.put("businessId", iotMaintainDO.getId());
                AdminUserRespDTO user = adminUserApi.getUser(Objects.isNull(failureReportDO.getAssigneeUserId()) ? Long.valueOf(failureReportDO.getCreator()) : failureReportDO.getAssigneeUserId());
//            notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
//                    .setUserId(failureReportDO.getAssigneeUserId()).setTemplateCode(PmsConstants.GENERATE_MAINTAIN).setTemplateParams(templateParams));
                if (Objects.nonNull(user)) {
                    if (Objects.nonNull(failureReportDO.getAssigneeUserId())) {
                        pmsMessage.sendMessage(iotMaintainDO.getId(), iotMaintainDO.getDeviceName(), PmsConstants.GENERATE_MAINTAIN, failureReportDO.getAssigneeUserId(), user.getMobile());
                    }
                }
            } else if (bpmResult ==3 ) {
                //更新故障上报状态及审核状态
                failureReportDO.setStatus("close");//关闭
                failureReportDO.setAuditStatus(FailureAuditStatusEnum.REJECT.getStatus());
                iotFailureReportMapper.insertOrUpdate(failureReportDO);
            }
        } else {
            //最终节点为否的情况下
            //首先更新故障上报的状态
            failureReportDO.setStatus("close");//关闭
            failureReportDO.setAuditStatus(FailureAuditStatusEnum.APPROVE.getStatus());
            iotFailureReportMapper.insertOrUpdate(failureReportDO);
            //更新设备状态为观察使用
            Long deviceId = failureReportDO.getDeviceId();
            IotDevicePersonRelationSaveReqVO statusVo = new IotDevicePersonRelationSaveReqVO();
            statusVo.setDeviceId(deviceId);
            statusVo.setStatus("gcsy");
            statusVo.setReason("没有生成维修工单，设备状态调整为观察使用");
            iotDevicePersonService.saveDeviceStatuses(ImmutableList.of(statusVo));
            IotDevicePersonPageReqVO pageReqVO = new IotDevicePersonPageReqVO();
            pageReqVO.setDeviceIds(ImmutableList.of(deviceId));
            List<IotDevicePersonDO> persons = iotDevicePersonService.getPersonsByDeviceIds(pageReqVO);
            persons.forEach(e ->{
                AdminUserRespDTO userApiUser = adminUserApi.getUser(e.getPersonId());
                if (Objects.nonNull(userApiUser)) {
                    pmsMessage.sendMessage(failureReportDO.getId(), failureReportDO.getDeviceCode()+failureReportDO.getDeviceName(), PmsConstants.FAILURE_NO_PASS, e.getPersonId(), userApiUser.getMobile());
                }
            });
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submitForApproval(Long id) {
        IotFailureReportDO iotFailureReportDO = iotFailureReportMapper.selectById(id);
//        if (Objects.isNull(iotFailureReportDO)) {throw new ServiceException(IOT_FAILURE_REPORT_NOT_EXISTS);}
        // 发起BPM流程
        // 获取当前登录人信息
        Map<String, List<Long>> assigness = new HashMap<>();
        List<Long> approvalIds = new ArrayList<>();
        for (String s : iotFailureReportDO.getApprovalId().split(",")) {
            approvalIds.add(Long.parseLong(s));
        }
        Map<String, Object> variable = new HashMap<>();
        String deviceCompany = iotDeviceService.getDeviceCompany(iotFailureReportDO.getDeviceId());
        String processInstanceId;
        if ("rh".equals(deviceCompany)) {
            assigness.put("rh_failure_approval", approvalIds);
            processInstanceId = processInstanceApi.createProcessInstance(SecurityFrameworkUtils.getLoginUserId(),
                    new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(RH_PROCESS_KEY).setBusinessKey(String.valueOf(id)).setStartUserSelectAssignees(assigness).setVariables(variable));
        } else {
            assigness.put("failure_approval", approvalIds);
            variable.put("continue", "0");
            processInstanceId = processInstanceApi.createProcessInstance(SecurityFrameworkUtils.getLoginUserId(),
                    new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY).setBusinessKey(String.valueOf(id)).setStartUserSelectAssignees(assigness).setVariables(variable));
        }
        // 将流程实例id 更新到 供应商主数据表
        iotFailureReportMapper.updateById(new IotFailureReportDO().setId(id).setProcessInstanceId(processInstanceId).setAuditStatus(FailureAuditStatusEnum.PROCESS.getStatus()));
        return processInstanceId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createIotFailureReport(IotFailureReportSaveReqVO createReqVO) {
        // 插入
        IotFailureReportDO iotFailureReport = BeanUtils.toBean(createReqVO, IotFailureReportDO.class);
        iotFailureReport.setFailureCode("GZ"+ DateUtil.format(new Date(), "yyMMdd"));
        IotDeviceDO iotDeviceDO = iotDeviceMapper.selectById(createReqVO.getDeviceId());
        if (Objects.isNull(iotDeviceDO)) {
            throw new ServiceException();
        }
        iotFailureReport.setFailureName(iotDeviceDO.getDeviceCode()+iotDeviceDO.getDeviceName()+DateUtil.format(new Date(), "yyMMddHHmm"));
        iotFailureReport.setDeviceName(iotDeviceDO.getDeviceName());
        iotFailureReport.setDeleted(false);
        if (iotFailureReport.getIfDeal()) {
            iotFailureReport.setStatus("finished");
            if (Objects.nonNull(iotFailureReport.getDealTime())) {
                BigDecimal v = DateUtils.calculateHoursDiff(iotFailureReport.getFailureTime(), iotFailureReport.getDealTime());
                iotFailureReport.setDealHour(v);
            }
            iotFailureReportMapper.insert(iotFailureReport);
        } else {
            iotFailureReport.setStatus("reporting");
            String deviceCompany = iotDeviceService.getDeviceCompany(iotFailureReport.getDeviceId());
            if ("rh".equals(deviceCompany)) {
                //如果为瑞恒的话，就设置为上一级项目部的副经理
                Long deptId = iotFailureReport.getDeptId();
                DeptRespDTO dept = deptApi.getDept(deptId);
                //如果为项目部的话，直接判断是塔河、塔里木还是吐哈。
                if ("2".equals(dept.getType())) {
                    if (Objects.nonNull(dept)) {
                        if ("塔河项目部".equals(dept.getName())){
                            iotFailureReport.setApprovalId("558");//窦文超
                            createReqVO.setApprovalId("558");//窦文超
                        } else if ("塔里木项目部".equals(dept.getName())) {
                            iotFailureReport.setApprovalId("150");//焦芳功
                            createReqVO.setApprovalId("150");//焦芳功
                        } else if ("吐哈项目部".equals(dept.getName())) {
                            iotFailureReport.setApprovalId("318");//王纯英
                            createReqVO.setApprovalId("318");//王纯英
                        }
                    }
                }else if ("3".equals(dept.getType())) {//如果是队伍的话
                    Long parentId = dept.getParentId();
                    if (Objects.nonNull(parentId)) {
                        DeptRespDTO dept1 = deptApi.getDeptNoPermission(parentId);
                        if (Objects.nonNull(dept1)) {
                            if ("塔河项目部".equals(dept1.getName())){
                                iotFailureReport.setApprovalId("558");//窦文超
                                createReqVO.setApprovalId("558");//窦文超
                            } else if ("塔里木项目部".equals(dept1.getName())) {
                                iotFailureReport.setApprovalId("150");//焦芳功
                                createReqVO.setApprovalId("150");//焦芳功
                            } else if ("吐哈项目部".equals(dept1.getName())) {
                                iotFailureReport.setApprovalId("318");//王纯英
                                createReqVO.setApprovalId("318");//王纯英
                            }
                        }
                    }
                }
            }
            if (StringUtils.isBlank(createReqVO.getApprovalId())||Objects.isNull(iotFailureReport.getApprovalId())) {
                throw new ServiceException(new ErrorCode(111,"无对应故障审批人"));
            }
            iotFailureReport.setAuditStatus(FailureAuditStatusEnum.PROCESS.getStatus());
            iotFailureReportMapper.insert(iotFailureReport);
            //直接发起流程
            String processInstanceId = submitForApproval(iotFailureReport.getId());
        }
        // 返回
        return iotFailureReport.getId();
    }

    private void sendMessage(IotFailureReportDO iotFailureReport, String processInstanceId) {
        Long loginUserDeptId = SecurityFrameworkUtils.getLoginUserDeptId();
        DeptDO dept = deptService.getDept(loginUserDeptId);
        Long deptId = dept.getParentId();
        List<Long> users = adminUserApi.getUserListByDept(deptId).stream().map(AdminUserRespDTO::getId).collect(Collectors.toList());
        List<Long> roleUserIds = roleApi.getRoleUserIds("公司设备管理");
        Set<Long> collect = users.stream().filter(roleUserIds::contains).collect(Collectors.toSet());
        Map<String, Object> templateParams = new HashMap<>();
        templateParams.put("businessType", PmsConstants.FAILURE_REPORT);
        templateParams.put("businessId", processInstanceId);
        templateParams.put("name", iotFailureReport.getDeviceName());
        CompletableFuture.runAsync(() -> collect.forEach(e->{
            notifyMessageSendApi.sendSingleMessageToAdmin(new NotifySendSingleToUserReqDTO()
                    .setUserId(e).setTemplateCode(PROCESS_KEY).setTemplateParams(templateParams));
            String msg = "【PMS】您有新的故障上报 - "+iotFailureReport.getFailureName()+"流程待审批。"+"["+new Date()+"]";
            AdminUserRespDTO user = adminUserApi.getUser(e);
            if (Objects.nonNull(user)) {
                dingtalkSendApi.send(user.getMobile(), msg,"","","DeepOil-PMS消息提醒");
            }
        }));
    }

    @Override
    public Long updateIotFailureReportProcess(IotFailureReportProcessVO processVO) {
        IotFailureReportDO reportDO = iotFailureReportMapper.selectById(processVO.getId());
        reportDO.setAssigneeUserId(processVO.getAssigneeUserId());
        reportDO.setType(processVO.getType());
        iotFailureReportMapper.insertOrUpdate(reportDO);
        //修改设备状态为待维修
        IotDevicePersonRelationSaveReqVO statusVo = new IotDevicePersonRelationSaveReqVO();
        statusVo.setDeviceId(reportDO.getDeviceId());
        statusVo.setStatus("dwx");
        statusVo.setReason("生成维修工单，设备状态为待维修");
        iotDevicePersonService.saveDeviceStatuses(ImmutableList.of(statusVo));
        //sendMessage(reportDO);
        return reportDO.getId();
    }

    @Override
    public void updateIotFailureReport(IotFailureReportSaveReqVO updateReqVO) {
        // 校验存在
        validateIotFailureReportExists(updateReqVO.getId());
        // 更新
        IotFailureReportDO updateObj = BeanUtils.toBean(updateReqVO, IotFailureReportDO.class);
        iotFailureReportMapper.updateById(updateObj);
    }

    @Override
    public void deleteIotFailureReport(Long id) {
        // 校验存在
        validateIotFailureReportExists(id);
        // 删除
        iotFailureReportMapper.deleteById(id);
    }

    private void validateIotFailureReportExists(Long id) {
        if (iotFailureReportMapper.selectById(id) == null) {
            throw exception(IOT_FAILURE_REPORT_NOT_EXISTS);
        }
    }

    @Override
    @DataPermission(enable = false)
    public IotFailureReportDO getIotFailureReport(Long id) {
        return iotFailureReportMapper.selectById(id);
    }

    @Override
    public List<AdminUserRespDTO> getApproval() {
        Long loginUserId = SecurityFrameworkUtils.getLoginUserId();
        AdminUserRespDTO user = adminUserApi.getUser(loginUserId);
        if (Objects.isNull(user)) {throw new ServiceException(111,"无该用户");}
        DeptRespDTO dept = deptApi.getDept(user.getDeptId());
        if (Objects.isNull(dept)) {throw new ServiceException(111,"无该部门");}

        List<Long> deptIds = deptApi.getChildDeptList(dept.getParentId()).stream().map(DeptRespDTO::getId).collect(Collectors.toList());
        deptIds.add(dept.getParentId());
//        List<Long> deptIds = new ArrayList<>();
//        deptIds.add(dept.getParentId());
        List<AdminUserRespDTO> userListByDeptId = adminUserApi.getUserListByDeptIdsNew(deptIds);
        return userListByDeptId;
    }

    @Override
    public PageResult<IotFailureReportDO> getIotFailureReportPage(IotFailureReportPageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        return iotFailureReportMapper.selectPage(pageReqVO, ids);
    }

    @Override
    public PageResult<IotFailureReportDO> getIotFailureReportPageApp(IotFailureReportPageReqVO pageReqVO) {
        Set<Long> ids = new HashSet<>();
        if (Objects.nonNull(pageReqVO.getDeptId())) {
            ids = deptService.getChildDeptIdListFromCache(pageReqVO.getDeptId());
            ids.add(pageReqVO.getDeptId());
        }
        return iotFailureReportMapper.selectPageApp(pageReqVO, ids);
    }

    @Override
    public void syncWordOrderData(List<Long> deviceIds, Long deptId) {
        List<IotFailureReportDO> failureReportDOS = iotFailureReportMapper.selectByStatusAndDeviceId(ImmutableList.of("finished", "orderfinished", "close"), deviceIds);
        failureReportDOS.forEach(failureReport -> {
            failureReport.setDeptId(deptId);
        });
        if(failureReportDOS.size()>0){
            iotFailureReportMapper.updateBatch(failureReportDOS);
        }
    }

}
