package com.xy.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xxl.job.core.biz.model.ReturnT;
import com.xy.device.EnumDeviceOfflineTimeOutCode;
import com.xy.device.EnumDeviceQrCode;
import com.xy.dto.*;
import com.xy.dto.be.MercDto;
import com.xy.dto.be.MercUserDeviceDto;
import com.xy.entity.DeviceInfo;
import com.xy.entity.DeviceNetRecord;
import com.xy.enums.ChannelType;
import com.xy.enums.MsgConfigId;
import com.xy.enums.MsgType;
import com.xy.mapper.DeviceNetRecordMapper;
import com.xy.service.be.MercFeignService;
import com.xy.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.xy.utils.Beans.copy;
import static com.xy.utils.PlusBeans.toIPage;
import static com.xy.utils.PlusBeans.toPageBean;

/**
 * <p>
 * 机器-联网记录job
 * </p>
 *
 * @author lijin
 * @since 2023-01-09
 */
@Slf4j
@Service
@AllArgsConstructor(onConstructor_ = @Lazy)
@Api(tags = "机器-联网记录")
public class DeviceNetRecordServiceImpl extends ServiceImpl<DeviceNetRecordMapper, DeviceNetRecord> implements DeviceNetRecordService {

    private  DeviceInfoServiceImpl deviceInfoService;
    private MercFeignService mercFeignService;
    private MsgSendApiService msgSendApiService;
    private UserInfoService userInfoService;
    private MsgSysMonitorNoticeService msgSysMonitorNoticeService;




    @PostMapping("save")
    @ApiOperation("添加")
    public R save(@RequestBody @Validated DeviceNetRecordDto.Save save) {
        DeviceNetRecord deviceNetRecord = copy(DeviceNetRecord.class, save)
                .setCreateTime(LocalDateTime.now());
        save(deviceNetRecord);
        return R.ok();
    }

    @Override
    @ApiOperation("分页查询")
    public R<PageBean<DeviceNetRecordDto.Vo>> page(@RequestBody DeviceNetRecordDto.Page page) {
        PageBean pageBean = page.getPage();
        LambdaQueryWrapper<DeviceNetRecord> lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(page, DeviceNetRecord.class)
                .ge(DeviceNetRecord::getCreateTime, page.getBeginCreateTime())
                .le(DeviceNetRecord::getCreateTime, page.getEndCreateTime())
                .build()
                .orderByDesc(!Emptys.check(pageBean.getOrders()), DeviceNetRecord::getCreateTime);
        IPage<DeviceNetRecord> iPage = page(toIPage(pageBean), lambdaQueryWrapper);
        return R.ok(toPageBean(DeviceNetRecordDto.Vo.class, iPage));
    }

    @PostMapping("list")
    @ApiOperation("集合查询")
    public R<List<DeviceNetRecordDto.Vo>> list(@RequestBody @Validated DeviceNetRecordDto.SelectList selectList) {
        LambdaQueryWrapper<DeviceNetRecord> lambdaQueryWrapper = new MybatisPlusQuery().eqWrapper(selectList, DeviceNetRecord.class)
                .in(DeviceNetRecord::getId, selectList.getIds())
                .in(DeviceNetRecord::getDeviceId, selectList.getDeviceIds())
                .in(DeviceNetRecord::getMercId, selectList.getMercIds())
                .in(DeviceNetRecord::getNetType, selectList.getNetTypes())
                .build();
        List<DeviceNetRecord> list = list(lambdaQueryWrapper);
        return R.ok(copy(DeviceNetRecordDto.Vo.class, list));
    }

    @PostMapping("offLineDevice")
    @ApiOperation("离线设备列表")
    public R<List<DeviceNetRecordDto.OffLineDeviceVo>> offLineDevice(@RequestBody @Validated DeviceNetRecordDto.OffLineDevice offLineDevice) {
        List<DeviceNetRecordDto.OffLineDeviceVo> offLineDeviceVos = baseMapper.offLineDevice(offLineDevice);
        return R.ok(offLineDeviceVos);
    }

    /**
     * 设备离线超时推送消息
     * @param deviceId
     */
    public void deviceOfflineTimeOutPushMsg(Long deviceId) {
        log.info("设备{}离线超时推送消息--->>>", deviceId);
        DeviceInfo deviceInfo = deviceInfoService.getById(deviceId);
            if (deviceInfo == null) {
                throw new RuntimeException("设备信息未找到，deviceId: " + deviceId);
            }
        String value = SysDictUtils.getValue(EnumDeviceOfflineTimeOutCode.Code.CODE.getCode(), EnumDeviceOfflineTimeOutCode.MINUTES.getCode(), String.class);
            Long mercId = deviceInfo.getMercId();

            MercDto.Vo merc = R.feignCheckData(mercFeignService.obj(new MercDto.ListDTO().setId(mercId)));
            if (merc == null) {
                throw new RuntimeException("商户信息未找到，mercId: " + mercId);
            }

            String mercCode = merc.getMercCode();
            Long configId = MercAuthUtils.sendMsgToCM(mercCode) ? MsgConfigId.CM_DEVICE_EXCEPTION.getId() : MsgConfigId.DEVICE_EXCEPTION.getId();
            MsgConfigDto.Vo msgConfig = R.feignCheckData(msgSendApiService.getMsgConfig(new MsgConfigDto.Vo().setId(configId)));
            if (msgConfig == null) {
                throw new RuntimeException("消息配置未找到，configId: " + configId);
            }

            List<MsgConfigTestDto.BizParam> bizParams = R.feignCheckData(msgSendApiService.getBizParamByMsgConfig(new MsgConfigTestDto.MsgConfig().setConfigId(configId)));
            if (CollUtil.isEmpty(bizParams)) {
                throw new RuntimeException("业务参数未找到，configId: " + configId);
            }

            List<MsgConfigTestDto.BizData> bizDataList = BeanUtil.copyToList(bizParams, MsgConfigTestDto.BizData.class);
            List<MsgConfigTestDto.BizData> sendList = new ArrayList<>();

            String deviceName = StrUtil.isEmpty(deviceInfo.getDeviceName()) ? String.valueOf(deviceId) : deviceInfo.getDeviceName() + "(" + deviceId + ")";
            Long userInfoId = merc.getUserInfoId();
            List<Long> userInfoIdList = new ArrayList<>();
            userInfoIdList.add(userInfoId);

            List<MercUserDeviceDto.Vo> mercUserDevices = R.feignCheckData(mercFeignService.mercDeviceUsers(new MercUserDeviceDto.Vo().setMercId(mercId).setDeviceId(deviceId)));
            if (CollUtil.isNotEmpty(mercUserDevices)) {
                mercUserDevices.forEach(mud -> {
                    if (Objects.equals(deviceId, mud.getDeviceId())) {
                        userInfoIdList.add(mud.getUserId());
                    }
                });
            }

            LocalDateTime createTime = LocalDateTime.now();
            StringBuilder sbMsg = StrUtil.builder()
                    .append("设备【").append(deviceName).append("】发生故障：设备已离线超过").append(value).append("分钟，发生时间：")
                    .append(DateUtil.format(createTime, DatePattern.NORM_DATETIME_PATTERN));

            List<UserInfoDto.Vo> userInfoList = R.feignCheckData(userInfoService.list(new UserInfoDto.SelectListDto().setUserIds(userInfoIdList)));
            if (CollUtil.isNotEmpty(userInfoList)) {
                userInfoList.forEach(u -> {
                    String name = u.getName();
                    // 系统消息
                    MsgSysMonitorNoticeDto.Save msgSys = new MsgSysMonitorNoticeDto.Save();
                    msgSys.setUserId(u.getAuthorizeUserId())
                            .setMsgType(MsgType.TYPE6.getCode())
                            .setContent(sbMsg.toString())
                            .setPubTime(LocalDateTime.now())
                            .setPubState(2)
                            .setSendTargets(name)
                            .setPriority(msgConfig.getPriority())
                            .setTitle("故障提醒")
                            .setEventCode("D011")
                            .setPubUserId(-1)
                            .setTitle(MsgType.TYPE6.getDescription());
                    msgSysMonitorNoticeService.save(msgSys);
                });

                for (MsgConfigTestDto.BizData b : bizDataList) {
                    if (ChannelType.OFFICIAL_ACCOUNT.getCode().equals(Integer.valueOf(b.getChannelType()))) {
                        Set<String> mpOpenIds = userInfoList.stream()
                                .filter(u -> ObjectUtil.isNotEmpty(u.getMpOpenid()))
                                .map(UserInfoDto.Vo::getMpOpenid)
                                .collect(Collectors.toSet());
                        if (CollUtil.isEmpty(mpOpenIds)) {
                            continue;
                        }

                        String msg = "设备已离线超过" + value + "分钟,请及时检查设备状态";
                        Map<String, Object> params = MapUtil.newHashMap();
                        if (MercAuthUtils.sendMsgToCM(mercCode)) {
                            params.put("character_string2", deviceId);
                            params.put("thing6", msg);
                            params.put("time8", DateUtil.format(createTime, DatePattern.NORM_DATETIME_PATTERN));
                        } else {
                            params.put("keyword1", deviceName);
                            params.put("keyword2", msg);
                            params.put("keyword3", DateUtil.format(createTime, DatePattern.NORM_DATETIME_PATTERN));
                        }

                        // 商户管理员发
                        b.setReceivers(mpOpenIds);
                        b.setTemplateParams(params);
                        sendList.add(b);
                    }
                }
            }

            // 是否可推送条件
            if (CollUtil.isNotEmpty(sendList)) {
                msgSendApiService.sendByMsgConfig(new MsgConfigTestDto.SendByMsgConfig().setConfigId(configId).setBizDataList(sendList));
            }

    }


}