package com.flossom.miniProgram.service.impl;

import com.flossom.common.core.domain.entity.*;
import com.flossom.common.core.domain.ret.WxBindingInstrumentInfo;
import com.flossom.common.core.domain.ret.WxModeRet;
import com.flossom.common.core.enums.*;
import com.flossom.common.core.exception.ServiceException;
import com.flossom.common.core.exception.ServiceReturnCodeException;
import com.flossom.common.core.mapper.*;
import com.flossom.common.core.utils.DateUtils;
import com.flossom.common.core.utils.StringUtils;
import com.flossom.common.security.utils.SecurityUtils;
import com.flossom.miniProgram.service.IWxInstrumentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;

import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.URL;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 仪器列Service业务层处理
 *
 * @author flossom
 * @date 2024-01-06
 */
@Service
public class WxInstrumentServiceImpl implements IWxInstrumentService {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private WxInstrumentMapper wxInstrumentMapper;

    @Autowired
    private WxInstrumentSerialMapper wxInstrumentSerialMapper;

    @Autowired
    private WxUserInstrumentMapper wxUserInstrumentMapper;

    @Autowired
    private WxUserInstrumentLogMapper wxUserInstrumentLogMapper;

    @Autowired
    private WxInstrumentFileRelateMapper wxInstrumentFileRelateMapper;

    @Autowired
    private WxInstrumentTagMapper wxInstrumentTagMapper;

    @Autowired
    private WxUserTagMapper wxUserTagMapper;

    @Autowired
    private WxUserMemberMapper wxUserMemberMapper;

    @Autowired
    private WxScriptMessageMapper wxScriptMessageMapper;

    @Autowired
    private WxUserScriptLogMapper wxUserScriptLogMapper;

    @Autowired
    private WxModeMapper wxModeMapper;

    @Autowired
    private WxModeTagMapper wxModeTagMapper;

    @Autowired
    private WxModeOpenSourceMapper wxModeOpenSourceMapper;

    @Autowired
    private WxModeCombineInfoMapper wxModeCombineInfoMapper;

    @Autowired
    private WxModeServiceInfoMapper wxModeServiceInfoMapper;

    @Override
    public List<WxInstrument> bindingInstrumentList() {
        /* 绑定了的仪器 不受 "可见小程序标签/可见外部标签" 影响， 去除仪器隐藏的 */
        return wxInstrumentMapper.selectBindingInstrumentListByUserId(SecurityUtils.getLoginUser().getWxUserMember().getId());
    }

    @Override
    public List<WxInstrument> unbindingInstrumentInfoList() {
        List<WxInstrument> returnList = new ArrayList<>();
        /* 去除仪器隐藏的 */
        List<WxInstrument> wxInstrumentList = wxInstrumentMapper.selectUnbindingInstrumentListByUserId(SecurityUtils.getLoginUser().getWxUserMember().getId());
        /* 未绑定的仪器 受 "可见小程序标签/可见外部标签" 影响，需要用户拥有全部对应的标签才可见 */
        if (wxInstrumentList != null && wxInstrumentList.size() > 0) {
            // 用户拥有的标签
            WxUserTag wxUserTag = new WxUserTag();
            wxUserTag.setUserId(SecurityUtils.getLoginUser().getWxUserMember().getId());
            List<WxUserTag> userTagList = wxUserTagMapper.selectWxUserTagList(wxUserTag);
            List<Long> userTagIdList;
            if (userTagList != null && userTagList.size() > 0) {
                userTagIdList = userTagList.stream().map(WxUserTag::getTagId).collect(Collectors.toList());
            } else {
                userTagIdList = null;
            }
            // 仪器标签
            for (WxInstrument wxInstrument : wxInstrumentList) {
                WxInstrumentTag wxInstrumentTag = new WxInstrumentTag();
                wxInstrumentTag.setInstrumentId(wxInstrument.getId());
                List<WxInstrumentTag> wxInstrumentTagList = wxInstrumentTagMapper.selectWxInstrumentTagList(wxInstrumentTag);
                if (wxInstrumentTagList != null && wxInstrumentTagList.size() > 0) {
                    List<Long> instrumentTagIdList = wxInstrumentTagList.stream().map(WxInstrumentTag::getTagId).collect(Collectors.toList());
                    if (userTagIdList == null || !userTagIdList.containsAll(instrumentTagIdList)) {
                        continue;
                    }
                }
                returnList.add(wxInstrument);
            }
        }
        return returnList;
    }

    @Override
    public WxInstrumentSerial getInstrumentInfoBySerial(String serial) {
        WxInstrumentSerial query = new WxInstrumentSerial();
        query.setSerial(serial);
        query.setValidStatus(SerialValidStatusEnums.EFFECTIVE.getCode());
        query.setStatus(Status.OK.getCode().longValue());
        WxInstrumentSerial wxInstrumentSerial = wxInstrumentSerialMapper.selectEntityListBySerial(query);
        // 序列号唯一
        if (wxInstrumentSerial == null) {
            logger.info("serial:{}, 序列号不存在", serial);
            throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_FIVE.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_FIVE.getCode());
        }
        return wxInstrumentSerial;
    }

    /**
     * @param serial               序列号
     * @param serialImage          序列号图片
     * @param isImmediatelyBinding 不立即绑定仪器，页面需要询问用户是否绑定
     *                             <p>
     *                             绑定流程中仪器 不受 "可见小程序标签/可见外部标签" 影响
     */
    @Override
    @Transactional
    public void binding(String serial, String serialImage, Boolean isImmediatelyBinding) {
        WxUserMember wxUserMember = wxUserMemberMapper.selectWxUserMemberById(SecurityUtils.getLoginUser().getWxUserMember().getId());
        /* 1、获取序列号信息 */
        WxInstrumentSerial wxInstrumentSerial = getInstrumentInfoBySerial(serial);

        /**
         * 2、判断当前用户是否绑定了序列号对应仪器的仪器ID
         *      （每个用户只能绑定一个仪器ID，当多个序列号对应的仪器ID一样时，则进行换绑）
         *          绑定了：
         *              1、序列号一致，直接获取仪器列表
         *              2、序列号不一致，询问是否对该仪器进行换绑
         *          没有绑定：
         *              1、是否有其他用户绑定，如果没有，开启绑定流程
         *              2、其他用户绑定了，返回联系客服
         */
        // 获取用户绑定了对应仪器的序列号
        WxUserInstrument userBindInstrumentQuery = new WxUserInstrument();
        userBindInstrumentQuery.setUserId(wxUserMember.getId());
        userBindInstrumentQuery.setInstrumentId(wxInstrumentSerial.getInstrumentId());
        userBindInstrumentQuery.setBindingStatus(BindingStatusEnums.BINDED.getCode());
        userBindInstrumentQuery.setStatus(Status.OK.getCode().longValue());
        List<WxUserInstrument> wxUserInstrumentList = wxUserInstrumentMapper.selectListByUserIdAndInstrumentId(userBindInstrumentQuery);
        // 2.1、当前用户绑定过序列号对应的仪器ID
        if (wxUserInstrumentList != null && wxUserInstrumentList.size() > 0) {
            if (wxUserInstrumentList.size() != 1) {
                logger.error("根据 用户id:{} 和 仪器id:{} 查询出来的数据为空或者数据量不止一条", wxUserMember.getId(), wxInstrumentSerial.getInstrumentId());
                throw new ServiceException("绑定失败");
            }
            WxUserInstrument wxUserInstrument = wxUserInstrumentList.get(0);
            /* 2.1.1、判断扫码获取的序列号和用户绑定的序列号是否一致 */
            if (!StringUtils.equals(wxUserInstrument.getSerial(), serial)) {
                /* 2.1.2、绑定过仪器，但不是同一个序列号，询问是否需要换绑 */
                logger.info("绑定过该类型仪器，但当前扫码的序列号与以前绑定的仪器的序列号不一致，询问用户是否换绑仪器");
                throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_TWO.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_TWO.getCode());
            }
            logger.info("扫码序列号与当前用户绑定的序列号一致，无需绑定，返回响应");
        }
        // 2.2、用户没有绑定过序列号对应的仪器ID
        else {
            // 不立即绑定
            if (!isImmediatelyBinding) {
                logger.info("可以绑定，但是不立即绑定，页面需要询问用户是否绑定");
                throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_ONE.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_ONE.getCode());
            }

            /* 2.2.1、判断序列号是否被别人绑定了 */
            WxUserInstrument query = new WxUserInstrument();
            query.setUserId(wxUserMember.getId());
            query.setSerial(serial);
            query.setStatus(Status.OK.getCode().longValue());
            query.setBindingStatus(BindingStatusEnums.BINDED.getCode());
            Integer num = wxUserInstrumentMapper.selectUiByInstrumentId(query);
            if (num != null && num > 0) {
                logger.info("被别人绑定了，页面跳转联系客服");
                throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_THREE.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_THREE.getCode());
            }
            /* 2.2.2、绑定仪器 */
            else {
                WxInstrument wxInstrument = wxInstrumentMapper.selectWxInstrumentById(wxInstrumentSerial.getInstrumentId());
                if (wxInstrument != null && wxInstrument.getStatus().intValue() == Status.DISABLE.getCode()) {
                    logger.info("仪器({})被隐藏了，无法绑定", wxInstrumentSerial.getInstrumentId());
                    throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_SIX.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_SIX.getCode());
                }

                // 构建 用户仪器关联对象
                WxUserInstrument saveEntity = new WxUserInstrument();
                saveEntity.setUserId(wxUserMember.getId());
                saveEntity.setSerial(serial);
                saveEntity.setSerialImage(serialImage);
                saveEntity.setInstrumentId(wxInstrumentSerial.getInstrumentId());
                saveEntity.setGuarantee(wxInstrument.getGuarantee());
                if (wxInstrument.getGuarantee() != null && wxInstrument.getGuarantee() >= 0) {
                    Instant instant = LocalDateTime.now().plusYears(wxInstrument.getGuarantee()).atZone(ZoneId.systemDefault()).toInstant();
                    saveEntity.setGuaranteeEndtime(Date.from(instant));
                }
                saveEntity.setBindingStatus(BindingStatusEnums.BINDED.getCode());
                saveEntity.setStatus(Status.OK.getCode().longValue());
                saveEntity.setUpdateBy(wxUserMember.getNickname());
                saveEntity.setUpdateTime(DateUtils.getNowDate());

                // 判断仪器是不是自己绑定过的，就是已解绑状态
                WxUserInstrument myBindingInstrumentQuery = new WxUserInstrument();
                myBindingInstrumentQuery.setUserId(wxUserMember.getId());
                myBindingInstrumentQuery.setInstrumentId(wxInstrumentSerial.getInstrumentId());
                myBindingInstrumentQuery.setBindingStatus(BindingStatusEnums.UN_BOUND.getCode());
                myBindingInstrumentQuery.setStatus(Status.OK.getCode().longValue());
                List<WxUserInstrument> myBindingInstrumentList = wxUserInstrumentMapper.selectListByUserIdAndInstrumentId(myBindingInstrumentQuery);
                if (myBindingInstrumentList != null && myBindingInstrumentList.size() > 0) {
                    // 解绑状态的仪器，重新绑定
                    WxUserInstrument wxUserInstrument = myBindingInstrumentList.get(0);
                    saveEntity.setId(wxUserInstrument.getId());
                    wxUserInstrumentMapper.updateWxUserInstrument(saveEntity);
                } else {
                    saveEntity.setCreateBy(wxUserMember.getNickname());
                    saveEntity.setCreateTime(DateUtils.getNowDate());
                    wxUserInstrumentMapper.insertWxUserInstrument(saveEntity);
                }

                // 更新仪器序列号绑定状态
                WxInstrumentSerial saveSerial = new WxInstrumentSerial();
                saveSerial.setId(wxInstrumentSerial.getId());
                saveSerial.setBindingStatus(BindingStatusEnums.BINDED.getCode());
                saveSerial.setUpdateBy(wxUserMember.getNickname());
                saveSerial.setUpdateTime(DateUtils.getNowDate());
                wxInstrumentSerialMapper.updateWxInstrumentSerial(saveSerial);

                // 保存绑定记录
                WxUserInstrumentLog wxUserInstrumentLog = new WxUserInstrumentLog();
                wxUserInstrumentLog.setUserInstrumentId(saveEntity.getId());
                wxUserInstrumentLog.setUserId(wxUserMember.getId());
                wxUserInstrumentLog.setSerial(serial);
                wxUserInstrumentLog.setSerialImage(saveEntity.getSerialImage());
                wxUserInstrumentLog.setInstrumentId(wxInstrument.getId());
                wxUserInstrumentLog.setInstrumentName(wxInstrument.getName());
                wxUserInstrumentLog.setGuarantee(wxInstrument.getGuarantee());
                wxUserInstrumentLog.setGuaranteeEndtime(saveEntity.getGuaranteeEndtime());
                wxUserInstrumentLog.setBindingStatus(BindingStatusEnums.BINDED.getCode());
                wxUserInstrumentLog.setStatus(Status.OK.getCode().longValue());
                wxUserInstrumentLog.setCreateBy(wxUserMember.getNickname());
                wxUserInstrumentLog.setCreateTime(DateUtils.getNowDate());
                wxUserInstrumentLog.setUpdateBy(wxUserMember.getNickname());
                wxUserInstrumentLog.setUpdateTime(DateUtils.getNowDate());
                wxUserInstrumentLogMapper.insertWxUserInstrumentLog(wxUserInstrumentLog);

                // 会员信息中的仪器数量加1
                WxUserMember updateDevicesNum = new WxUserMember();
                updateDevicesNum.setId(wxUserMember.getId());
                updateDevicesNum.setDevicesNum(wxUserMember.getDevicesNum() + 1);
                // 仪器绑定积分
                updateDevicesNum.setCredit(wxUserMember.getCredit() + wxInstrument.getBindingCredit());
                wxUserMemberMapper.updateWxUserMember(updateDevicesNum);

                // 绑定成功发送消息
                WxScriptMessage wxScriptMessage = wxScriptMessageMapper.selectOneByMessageType(MessageTypeEnum.BINDING_INSTRUMENTS.getCode());
                if (wxScriptMessage != null) {
                    WxUserScriptLog wxUserScriptLog = new WxUserScriptLog();
                    BeanUtils.copyProperties(wxScriptMessage, wxUserScriptLog);
                    wxUserScriptLog.setId(null);
                    wxUserScriptLog.setWxUserId(wxUserMember.getId());
                    wxUserScriptLog.setMessageType(WxUserIntegralMessageTypeEnum.BINDING_INSTRUMENTS.getCode());
                    wxUserScriptLog.setIsCustom(0);
                    wxUserScriptLog.setTitile(wxScriptMessage.getMessageTitle());
                    wxUserScriptLog.setContent(wxScriptMessage.getMessageContent());
                    wxUserScriptLog.setCreateTime(DateUtils.getNowDate());
                    wxUserScriptLog.setCreateBy(null);
                    wxUserScriptLog.setUpdateTime(null);
                    wxUserScriptLog.setUpdateBy(null);
                    wxUserScriptLogMapper.insertWxUserScriptLog(wxUserScriptLog);
                }

                /**
                 * TODO: 仪器绑定与数云同步积分
                 */
            }
        }
    }

    @Override
    @Transactional
    public void exchangeBinding(String serial) {
        WxUserMember wxUserMember = SecurityUtils.getLoginUser().getWxUserMember();
        /* 1、获取序列号信息 */
        WxInstrumentSerial newInstrumentSerial = getInstrumentInfoBySerial(serial);

        /* 2、判断序列号是否被别人绑定了 */
        WxUserInstrument query = new WxUserInstrument();
        query.setUserId(wxUserMember.getId());
        query.setSerial(serial);
        query.setStatus(Status.OK.getCode().longValue());
        query.setBindingStatus(BindingStatusEnums.BINDED.getCode());
        Integer num = wxUserInstrumentMapper.selectUiByInstrumentId(query);
        if (num != null && num > 0) {
            logger.info("被别人绑定了，页面跳转联系客服");
            throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_THREE.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_THREE.getCode());
        }
        WxInstrument wxInstrument = wxInstrumentMapper.selectWxInstrumentById(newInstrumentSerial.getInstrumentId());
        if (wxInstrument != null && wxInstrument.getStatus().intValue() == Status.DISABLE.getCode()) {
            logger.info("仪器({})被隐藏了，无法绑定", newInstrumentSerial.getInstrumentId());
            throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_SIX.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_SIX.getCode());
        }

        /* 3、换绑 */
        // 3.1、查询原记录
        WxUserInstrument userInstrumentQuery = new WxUserInstrument();
        userInstrumentQuery.setUserId(wxUserMember.getId());
        userInstrumentQuery.setInstrumentId(newInstrumentSerial.getInstrumentId());
        userInstrumentQuery.setStatus(Status.OK.getCode().longValue());
        List<WxUserInstrument> wxUserInstrumentList = wxUserInstrumentMapper.selectListByUserIdAndInstrumentId(userInstrumentQuery);
        if (wxUserInstrumentList == null || wxUserInstrumentList.size() != 1) {
            logger.error("根据 用户id:{} 和 仪器id:{} 查询出来的数据为空或者数据量不止一条", wxUserMember.getId(), newInstrumentSerial.getInstrumentId());
            throw new ServiceException("换绑失败");
        }
        WxUserInstrument wxUserInstrument = wxUserInstrumentList.get(0);

        // 3.2、更新旧的序列号状态为已解绑
        // 当后管解除了用户和仪器的绑定，状态变为已解绑，无需再次修改序列号的绑定状态
        if (BindingStatusEnums.UN_BOUND.getCode() == wxUserInstrument.getBindingStatus()) {
            WxInstrumentSerial oldUpdate = new WxInstrumentSerial();
            oldUpdate.setBindingStatus(BindingStatusEnums.UN_BOUND.getCode());
            oldUpdate.setSerial(wxUserInstrument.getSerial());
            wxInstrumentSerialMapper.updateBySerial(oldUpdate);
        }
        // 3.3、更新新的序列号状态为已绑定
        WxInstrumentSerial newUpdate = new WxInstrumentSerial();
        newUpdate.setBindingStatus(BindingStatusEnums.BINDED.getCode());
        newUpdate.setSerial(serial);
        wxInstrumentSerialMapper.updateBySerial(newUpdate);
        // 3.4、更新用户仪器关联表
        WxUserInstrument updateEntity = new WxUserInstrument();
        updateEntity.setId(wxUserInstrument.getId());
        updateEntity.setSerial(serial);
        if (wxUserInstrument.getGuarantee() != null && wxUserInstrument.getGuarantee() >= 0) {
            Instant instant = LocalDateTime.now().plusYears(wxUserInstrument.getGuarantee()).atZone(ZoneId.systemDefault()).toInstant();
            updateEntity.setGuaranteeEndtime(Date.from(instant));
        }
        // 当后管解除了用户和仪器的绑定，状态变为已解绑，此时就需改为绑定状态
        updateEntity.setBindingStatus(BindingStatusEnums.BINDED.getCode());
        updateEntity.setUpdateBy(wxUserMember.getNickname());
        updateEntity.setUpdateTime(DateUtils.getNowDate());
        wxUserInstrumentMapper.updateWxUserInstrument(updateEntity);
        // 3.5、用户仪器关联记录表
        // 当后管解除了用户和仪器的绑定，操作记录已记录，无需再次记录
        if (BindingStatusEnums.UN_BOUND.getCode() == wxUserInstrument.getBindingStatus()) {
            WxUserInstrumentLog oldUserInstrumentLog = new WxUserInstrumentLog();
            oldUserInstrumentLog.setUserInstrumentId(wxUserInstrument.getId());
            oldUserInstrumentLog.setUserId(wxUserMember.getId());
            oldUserInstrumentLog.setSerial(wxUserInstrument.getSerial());
            oldUserInstrumentLog.setInstrumentId(wxUserInstrument.getInstrumentId());
            oldUserInstrumentLog.setInstrumentName(wxInstrument.getName());
            oldUserInstrumentLog.setSerialImage(wxUserInstrument.getSerialImage());
            oldUserInstrumentLog.setGuarantee(wxUserInstrument.getGuarantee());
            oldUserInstrumentLog.setGuaranteeEndtime(wxUserInstrument.getGuaranteeEndtime());
            oldUserInstrumentLog.setBindingStatus(BindingStatusEnums.UN_BOUND.getCode());
            oldUserInstrumentLog.setStatus(Status.OK.getCode().longValue());
            oldUserInstrumentLog.setCreateBy(wxUserMember.getNickname());
            oldUserInstrumentLog.setCreateTime(DateUtils.getNowDate());
            wxUserInstrumentLogMapper.insertWxUserInstrumentLog(oldUserInstrumentLog);
        }
        WxUserInstrumentLog newUserInstrumentLog = new WxUserInstrumentLog();
        newUserInstrumentLog.setUserInstrumentId(wxUserInstrument.getId());
        newUserInstrumentLog.setUserId(wxUserMember.getId());
        newUserInstrumentLog.setSerial(serial);
        newUserInstrumentLog.setInstrumentId(wxUserInstrument.getInstrumentId());
        newUserInstrumentLog.setInstrumentName(wxInstrument.getName());
        newUserInstrumentLog.setSerialImage(wxUserInstrument.getSerialImage());
        newUserInstrumentLog.setGuarantee(wxUserInstrument.getGuarantee());
        newUserInstrumentLog.setGuaranteeEndtime(updateEntity.getGuaranteeEndtime());
        newUserInstrumentLog.setBindingStatus(BindingStatusEnums.BINDED.getCode());
        newUserInstrumentLog.setStatus(Status.OK.getCode().longValue());
        newUserInstrumentLog.setCreateBy(wxUserMember.getNickname());
        newUserInstrumentLog.setCreateTime(DateUtils.getNowDate());
        wxUserInstrumentLogMapper.insertWxUserInstrumentLog(newUserInstrumentLog);
    }

    @Override
    public List<WxInstrumentFileRelate> getInstrumentFileRelateByInstrumentId(Long instrumentId, Integer classify) {
        WxInstrumentFileRelate wxInstrumentFileRelate = new WxInstrumentFileRelate();
        wxInstrumentFileRelate.setInstrumentId(instrumentId);
        wxInstrumentFileRelate.setClassify(classify);
        wxInstrumentFileRelate.setStatus(Status.OK.getCode().longValue());
        return wxInstrumentFileRelateMapper.selectWxInstrumentFileRelateList(wxInstrumentFileRelate);
    }

    @Override
    public List<WxModeRet> getInstrumentModeByInstrumentId(Long instrumentId) {
        // 用户拥有的标签
        WxUserTag wxUserTag = new WxUserTag();
        wxUserTag.setUserId(SecurityUtils.getLoginUser().getWxUserMember().getId());
        List<WxUserTag> userTagList = wxUserTagMapper.selectWxUserTagList(wxUserTag);
        List<Long> userTagIdList;
        if (userTagList != null && userTagList.size() > 0) {
            userTagIdList = userTagList.stream().map(WxUserTag::getTagId).collect(Collectors.toList());
        } else {
            userTagIdList = null;
        }
        // 查询仪器关联的所有模式
        List<WxModeRet> wxModeRetList = new ArrayList<>();
        List<WxMode> wxModeList = wxModeMapper.selectListByInstrumentId(instrumentId);
        for (WxMode wxMode : wxModeList) {
            // 判断每个模式是否加锁
            WxModeRet wxModeRet = new WxModeRet();
            WxModeTag wxModeTag = new WxModeTag();
            wxModeTag.setModeId(wxMode.getId());
            List<WxModeTag> wxModeTagList = wxModeTagMapper.selectWxModeTagList(wxModeTag);
            BeanUtils.copyProperties(wxMode, wxModeRet);
            wxModeRet.setModeTime(LocalTime.of(0, wxMode.getModeTime()));
            Boolean isLock = false;
            if (wxModeTagList != null && wxModeTagList.size() > 0) {
                List<Long> modeTagList = wxModeTagList.stream().map(WxModeTag::getTagId).collect(Collectors.toList());
                if (userTagIdList == null || userTagIdList.size() == 0 || !userTagIdList.containsAll(modeTagList)) {
                    wxModeRet.setLock(true);
                    isLock = true;
                }
            }
            if (!isLock) {
                wxModeRet.setLock(false);
            }
            // 查询 模式组合
            WxModeCombineInfo query = new WxModeCombineInfo();
            query.setModeId(wxMode.getId());
            wxModeRet.setCombineData(wxModeCombineInfoMapper.selectWxModeCombineInfoList(query));
            // 查询 弹窗集合
            WxModeOpenSource wxModeOpenSource = new WxModeOpenSource();
            wxModeOpenSource.setModeId(wxMode.getId());
            wxModeRet.setOpenSourceData(wxModeOpenSourceMapper.selectWxModeOpenSourceList(wxModeOpenSource));
            // 查询 服务集合
            WxModeServiceInfo wxModeServiceInfo = new WxModeServiceInfo();
            wxModeServiceInfo.setModeId(wxMode.getId());
            wxModeRet.setServiceData(wxModeServiceInfoMapper.selectWxModeServiceInfoList(wxModeServiceInfo));

            // 将 localTime 转为 分秒 格式
            if (wxModeRet.getModeTime() != null) {
                wxModeRet.setModeTimeStr(String.format("%02d:%02d", wxModeRet.getModeTime().getMinute(), wxModeRet.getModeTime().getSecond()));
            }
            wxModeRetList.add(wxModeRet);
        }
        return wxModeRetList;
    }

    /**
     * 判断序列号对应的仪器，与instrumentId是否一致
     */
    @Override
    public WxInstrumentSerial determineSerialIsSameInstrument(String serial, Long instrumentId) {
        /* 1、获取序列号信息 */
        WxInstrumentSerial wxInstrumentSerial = getInstrumentInfoBySerial(serial);
        if (wxInstrumentSerial.getInstrumentId() != instrumentId) {
            logger.info("用户选择的仪器与序列号对应的仪器不一致，序列号：{}， 仪器ID：{}", serial, instrumentId);
            throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_FOUR.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_FOUR.getCode());
        }
        WxInstrument wxInstrument = wxInstrumentMapper.selectWxInstrumentById(wxInstrumentSerial.getInstrumentId());
        if (wxInstrument != null && wxInstrument.getStatus().intValue() == Status.DISABLE.getCode()) {
            logger.info("仪器({})被隐藏了，无法绑定", wxInstrumentSerial.getInstrumentId());
            throw new ServiceReturnCodeException(InstrumentHttpCodeEnum.TWO_HUNDRED_AND_SIX.getInfo(), InstrumentHttpCodeEnum.TWO_HUNDRED_AND_SIX.getCode());
        }
        return wxInstrumentSerial;
    }

    @Override
    public String upgrade(Long instrumentId, Boolean isWe200) {
        WxInstrument wxInstrument = wxInstrumentMapper.selectWxInstrumentById(instrumentId);
        if (wxInstrument != null && StringUtils.isNotBlank(wxInstrument.getIotUpgradeData())) {
            // 读取文件系统中的文件
            try {
                byte[] byteArray;
                if (isWe200) {
                    byteArray = FileCopyUtils.copyToByteArray(new URL(wxInstrument.getWe200IotUpgradeData()).openStream());
                } else {
                    byteArray = FileCopyUtils.copyToByteArray(new URL(wxInstrument.getIotUpgradeData()).openStream());
                }
                return DatatypeConverter.printHexBinary(byteArray);
            } catch (FileNotFoundException e) {
                logger.error("instrumentId:{} 升级失败: {}", instrumentId, e.getMessage());
                throw new ServiceException("升级失败");
            } catch (IOException e) {
                logger.error("instrumentId:{} 升级失败: {}", instrumentId, e.getMessage());
                throw new ServiceException("升级失败");
            }
        }
        return null;
    }

    @Override
    public WxBindingInstrumentInfo bindingInstrumentInfo(Long instrumentId) {
        WxUserMember wxUserMember = SecurityUtils.getLoginUser().getWxUserMember();
        WxUserInstrument query = new WxUserInstrument();
        query.setUserId(wxUserMember.getId());
        query.setInstrumentId(instrumentId);
        query.setBindingStatus(BindingStatusEnums.BINDED.getCode());
        List<WxUserInstrument> wxUserInstrumentList = wxUserInstrumentMapper.selectListByUserIdAndInstrumentId(query);
        if (wxUserInstrumentList == null || wxUserInstrumentList.size() != 1) {
            throw new ServiceException("没有绑定该仪器");
        }
        WxUserInstrument wxUserInstrument = wxUserInstrumentList.get(0);
        WxInstrument wxInstrument = wxInstrumentMapper.selectWxInstrumentById(instrumentId);
        // 封装返回信息
        WxBindingInstrumentInfo wxBindingInstrumentInfo = new WxBindingInstrumentInfo();
        wxBindingInstrumentInfo.setInstrumentId(wxInstrument.getId());
        wxBindingInstrumentInfo.setInstrumentName(wxInstrument.getName());
        wxBindingInstrumentInfo.setInstrumentType(wxInstrument.getType());
        wxBindingInstrumentInfo.setInstrumentModel(wxInstrument.getModel());
        wxBindingInstrumentInfo.setInstrumentBanner(wxInstrument.getBanner());
        wxBindingInstrumentInfo.setInstrumentLogo(wxInstrument.getLogo());
        wxBindingInstrumentInfo.setInstrumentSerialImageLocation(wxInstrument.getSerial());
        wxBindingInstrumentInfo.setBindingSerial(wxUserInstrument.getSerial());
        wxBindingInstrumentInfo.setBindingSerialImage(wxUserInstrument.getSerialImage());
        wxBindingInstrumentInfo.setInstrumentGuarantee(wxUserInstrument.getGuarantee());
        wxBindingInstrumentInfo.setInstrumentNursingTime(wxInstrument.getNursingTime());
        wxBindingInstrumentInfo.setInstrumentIotVersion(wxInstrument.getIotVersion());
        wxBindingInstrumentInfo.setInstrumentIotUpgradeData(wxInstrument.getIotUpgradeData());
        wxBindingInstrumentInfo.setInstrumentIsScanCode(wxInstrument.getIsScanCode());
        wxBindingInstrumentInfo.setInstrumentIsPurchase(wxInstrument.getIsPurchase());
        wxBindingInstrumentInfo.setBindingDateTime(wxUserInstrument.getUpdateTime());
        return wxBindingInstrumentInfo;
    }
}
