package com.xy.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.BooleanUtil;
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.toolkit.Wrappers;
import com.github.yitter.idgen.YitIdHelper;
import com.xy.annotate.RestMappingController;
import com.xy.annotation.LogOperate;
import com.xy.collections.list.JArrayList;
import com.xy.collections.map.JMap;
import com.xy.device.EnumDeviceActiveStatus;
import com.xy.device.EnumDeviceFreezeStatus;
import com.xy.dto.*;
import com.xy.dto.be.MercDto;
import com.xy.dto.common.MercPlaceDto;
import com.xy.entity.*;
import com.xy.enums.LogEnum;
import com.xy.enums.MercStatus;
import com.xy.service.*;
import com.xy.service.be.MercFeignService;
import com.xy.service.common.MercLineService;
import com.xy.service.common.MercPlaceService;
import com.xy.service.factory.device.DeviceFactory;
import com.xy.utils.*;
import com.xy.utils.Enum.AlgorithmTypeEnum;
import com.xy.utils.enums.DeviceActiveStateEnum;
import com.xy.utils.enums.DeviceAuthCodeUseStatus;
import com.xy.utils.enums.DeviceLockState;
import com.xy.utils.enums.DeviceNetSateType;
import com.xy.vo.DeviceDetailVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.xy.utils.Beans.copy;

/**
 * <p>
 * 小程序-设备
 * </p>
 *
 * @author hechunping
 * @since 2023/3/4
 */
@RestMappingController("merc-mini/device")
@AllArgsConstructor
@Api(tags = "小程序-设备")
@Slf4j
public class MercMiniDeviceController {

    /**
     * auth-code有效期30分钟，单位：s ,
     */
    public static final Integer AUTH_CODE_TIMEOUT = 1800;
    private final MercFeignService mercFeignService;
    private final DeviceInfoServiceImpl deviceInfoService;
    private final DeviceSysinfoServiceImpl deviceSysinfoService;
    private final MercPlaceService mercPlaceService;
    private final MercLineService mercLineService;
    private final DeviceBluetoothAuthServiceImpl deviceBluetoothAuthService;
    private final DeviceTempRecordsServiceImpl deviceTempRecordsService;
    private final AlipayDeviceService alipayDeviceService;
    private final DeviceStatusServiceImpl deviceStatusService;
    private final DeviceConfigServiceImpl deviceConfigService;
    private final DeviceTempSetServiceImpl deviceTempSetService;

    public static void setCacheAuthCode(Long deviceId, String code) {
        RedisService<String> redisService = SpringBeanUtils.getBean(RedisService.class);
        redisService.set("device:auth:code:" + deviceId, code, AUTH_CODE_TIMEOUT);
    }

    public static String getCacheAuthCode(Long deviceId) {
        RedisService<String> redisService = SpringBeanUtils.getBean(RedisService.class);
        return redisService.get("device:auth:code:" + deviceId);
    }

    public static void delCacheAuthCode(Long deviceId) {
        RedisService<String> redisService = SpringBeanUtils.getBean(RedisService.class);
        redisService.remove("device:auth:code:" + deviceId);
    }

    @LogOperate(logType = LogEnum.LogType.V2, optType = LogEnum.OptType.V2, logContent = "解绑商户")
    @ApiOperation("解绑商户")
    @PostMapping("unBindMercDevice")
    R<Boolean> unBindMercDevice(@RequestBody @Validated DeviceInfoDto.MercDeviceUnBindDto dto) {
        MercAuthUtils.MercAuth.Merc merc = MercAuthUtils.getMercAuth().getMerc();
        dto.setMercId(merc.getId());
        dto.setMercCode(merc.getMercCode());
        dto.setMercName(merc.getName());
        List<Long> deviceIds = dto.getDeviceIds();
        String log = String.format("解绑商户：被解绑商户：%s,解绑设备：%s", merc.getId() + "," + merc.getName(), CollUtil.isEmpty(deviceIds) ? "" : CollUtil.join(deviceIds, ","));
        return R.ok(deviceInfoService.unBindDeviceByMerc(dto)).setLogMsg(log);
    }

    @LogOperate(logType = LogEnum.LogType.V2, optType = LogEnum.OptType.V2, logContent = "商户设备授权")
    @ApiOperation("商户设备授权")
    @PostMapping("deviceAuth")
    public R mercDeviceAuth(@RequestBody @Validated DeviceInfoDto.MercDeviceAuthDto auth) {
        String mercCode = auth.getMercCode();
        MercDto.Vo merc = R.feignCheckData(mercFeignService.obj(new MercDto.ListDTO().setMercCode(mercCode)));
//        MercAuthUtils.MercAuth.Merc merc = MercAuthUtils.getMercAuth().getMerc();
        auth.setMercCode(mercCode);
        auth.setMercId(merc.getId());
        auth.setParentId(merc.getParentId());
        auth.setMercName(merc.getName());
        auth.setAlgorithmId(merc.getAlgorithmId());
        auth.setMercOperate(true);
        // 设备服务授权处理
        R<Boolean> r = R.feignCheck(deviceInfoService.mercDeviceAuth(auth));
        List<Long> deviceIds = auth.getDeviceIds();
        String log = String.format("商户设备授权：授权商户：%s,授权设备：%s", merc.getId() + "," + merc.getName(), deviceIds.size() == 0 ? "取消所有设备授权" : CollUtil.join(deviceIds, ","));
        return R.ok(r.getData()).setLogMsg(log);
    }

    @ApiOperation("设备分页-管理员")
    @PostMapping("pageByAdminName")
    public R<PageBean<DeviceInfoDto.ListByAdminName>> pageByAdminName(@RequestBody @Validated DeviceInfoDto.PageByAdminNameDto dto) {
        dto.setMercId(MercAuthUtils.getMercId());
        dto.setDeviceIdList(getMyDevices());
        dto.setPage(dto.getPage().setOrders(null));
        return deviceInfoService.pageByAdminName(dto);
    }

    @ApiOperation("设备分页-商户")
    @PostMapping("pageByMerc")
    public R<PageBean<DeviceInfoDto.Vo>> pageByMerc(@RequestBody @Validated DeviceInfoDto.PageByMercDto dto) {
        List<Long> deviceIds = dto.getDeviceIds();
        dto.setMercId(MercAuthUtils.getMercId());
        Boolean choosed = dto.getChoosed();
        if (BooleanUtil.isTrue(choosed)) {
            // 查询已选择，为前端传入 deviceIds
            dto.setDeviceIds(deviceIds);
        }
        dto.setMyDeviceIds(getMyDevices());
        return R.ok(deviceInfoService.pageByMerc(dto));
    }

    @ApiOperation("商户设备列表分页-穿梭框用")
    @PostMapping("myDeviceList")
    public R<PageBean<DeviceInfoDto.MyDeviceInfo>> myDeviceList(@RequestBody @Validated DeviceInfoDto.MyDeviceDTO dto) {
        dto.setMercId(MercAuthUtils.getMercId());
        return deviceInfoService.myDeviceList(dto);
    }

    @ApiOperation("设备列表带卡包数")
    @PostMapping("algorithmChargingDevice")
    public R<PageBean<DeviceInfoDto.AlgorithmChargingVo>> algorithmChargingDevice(@RequestBody @Validated DeviceInfoDto.AlgorithmCharging algorithmCharging) {
        algorithmCharging.setMercId(MercAuthUtils.getMercId());
        return deviceInfoService.algorithmChargingDevice(algorithmCharging);
    }

    @ApiOperation("商户设备首页统计")
    @PostMapping("mercHomeStatistical")
    public R<DeviceInfoDto.MercHomeStatisticalVO> mercHomeStatistical(@RequestBody @Valid DeviceInfoDto.MercHomeQueryDTO dto) {
        dto.setMercId(MercAuthUtils.getMercId());
        dto.setMyDeviceIds(getMyDevices());
        return deviceInfoService.mercHomeStatistical(dto);
    }

    @ApiOperation("设备列表-Id&Name")
    @PostMapping("listOfIdName")
    public R listOfIdName() {
        DeviceInfoDto.ListCommon listCommonDto = new DeviceInfoDto.ListCommon();
        DeviceInfoDto.Vo voDto = new DeviceInfoDto.Vo();
        voDto.setActiveState(Integer.valueOf(DeviceActiveStateEnum.TRUE.getCode()))
                .setMercId(MercAuthUtils.getMercId());
        listCommonDto.setVo(voDto);
        List<MercMiniDeviceDto.ListOfIdNameVo> copy = copy(MercMiniDeviceDto.ListOfIdNameVo.class, deviceInfoService.listCommon(listCommonDto).getData());
        return R.ok(copy);
    }

    @PostMapping("searchPage")
    @ApiOperation("小程序商户设备搜索")
    public R<PageBean<DeviceInfoDto.MerHomeSearchVO>> mercDeviceSearchPage(@RequestBody DeviceInfoDto.Page page) {
        page.setMercId(MercAuthUtils.getMercId());
        page.setMyDeviceIds(getMyDevices());
        return deviceInfoService.mercDeviceSearchPage(page);
    }

    @PostMapping("simpleDeviceSearchPage")
    @ApiOperation("小程序-通用商户设备搜索组件")
    public R<PageBean<DeviceInfoDto.SimpleDeviceSearchPageVo>> simpleDeviceSearchPage(@RequestBody DeviceInfoDto.SimpleDeviceSearchPageDto page) {
        page.setMercId(MercAuthUtils.getMercId());
        page.setMyDeviceIds(getMyDevices());
        return deviceInfoService.simpleDeviceSearchPage(page);
    }

    @ApiOperation("小程序商户设备详情-设备信息")
    @PostMapping("detail")
    R<DeviceInfoDto.Vo> detail(@RequestBody DeviceInfoDto.Obj obj) {
        obj.setMercId(MercAuthUtils.getMercId());
        obj.setIsStatus(true);
        R<DeviceInfoDto.Vo> r = deviceInfoService.obj(obj);
        DeviceInfoDto.Vo vo = r.getData();
        if (vo != null) {
            Long algorithmId = vo.getAlgorithmId();
            // 点位
            Long placeId = vo.getPlaceId();
            List<MercPlaceDto.Vo> merPlaceList = R.feignCheckData(mercPlaceService.list(new MercPlaceDto.ListDto().setIds(CollUtil.newArrayList(placeId))));
            MercPlaceDto.Vo mercPlace = CollUtil.isNotEmpty(merPlaceList) ? merPlaceList.get(0) : null;
            if (Emptys.check(mercPlace)) {
                vo.setDistrictName(mercPlace.getRegionName());
                vo.setPlaceName(mercPlace.getPlaceName());
                vo.setPlaceImgs(mercPlace.getImgs());
            }

            // 返显区域名称

            DeviceStatusDto.Vo deviceStatus = vo.getDeviceStatus();
            vo.setNetStateName(deviceStatus == null ? StrUtil.EMPTY : DeviceNetSateType.getEnumByCode(deviceStatus.getNetState()).getDescription());
            if (deviceStatus != null) {
                Integer tempValue = deviceStatus.getTempValue();
                if (tempValue == null) {
                    List<DeviceTempRecords> deviceTempRecords = deviceTempRecordsService
                            .list(Wrappers.<DeviceTempRecords>lambdaQuery()
                                    .eq(DeviceTempRecords::getDeviceId, vo.getDeviceId()).orderByDesc(DeviceTempRecords::getCreateTime).last("limit 1")
                            );
                    if (CollUtil.isNotEmpty(deviceTempRecords)) {
                        deviceStatus.setTempValue(deviceTempRecords.get(0).getTempValue());
                        vo.setDeviceStatus(deviceStatus);
                    } else {
                        deviceStatus.setTempValue(0);
                        vo.setDeviceStatus(deviceStatus);
                    }
                }

                Integer deviceStateL = deviceStatus.getLockStateL();
                Integer deviceStateR = deviceStatus.getLockStateR();
                Boolean isUseBattery = deviceStatus.getIsUseBattery();
                if (BooleanUtil.isTrue(isUseBattery)) {
                    // 使用电池。即断电状态
                    vo.setSysPower(2);
                } else {
                    vo.setSysPower(1);
                }
                vo.setDeviceStateL(deviceStateL);
                vo.setDeviceStateR(deviceStateR);
                DeviceLockState deviceLockStateL = DeviceLockState.getEnumByCode(deviceStateL);
                DeviceLockState deviceLockStateR = DeviceLockState.getEnumByCode(deviceStateR);
                vo.setDeviceStateRName(deviceLockStateR == null ? "未知" : deviceLockStateR.getDescription());
                vo.setDeviceStateLName(deviceLockStateL == null ? "未知" : deviceLockStateL.getDescription());

                if (AlgorithmTypeEnum.ALIPAY.getId() == algorithmId) {
                    String deviceId = String.valueOf(vo.getDeviceId());
                    // 主动查询一次温度、音量 温度：TEMP 音量：VOL
                    alipayDeviceService.queryAttributes(new DeviceQueryAttr().setTerminalId(deviceId).setType("VOL"));
                    alipayDeviceService.queryAttributes(new DeviceQueryAttr().setTerminalId(deviceId).setType("TEMP"));
                    // 支付宝状态实时返回
                    DeviceDetailVO deviceDetailVO = alipayDeviceService.queryDetail(new DeviceDetailDTO().setTerminalId(String.valueOf(vo.getDeviceId())));
                    Boolean online = deviceDetailVO.getOnline();
                    Integer netState = BooleanUtil.isTrue(online) ? DeviceNetSateType.CONNECTED.getCode() : DeviceNetSateType.DISCONNECT.getCode();
                    if (!ObjectUtil.equals(netState, deviceStatus.getNetState())) {
                        // 存在差异更新设备状态表
                        deviceStatusService.updateById(new DeviceStatus().setDeviceId(vo.getDeviceId()).setNetState(netState));
                    }
                    deviceStatus.setNetState(netState);
                    vo.setDeviceStatus(deviceStatus);
                }
            }
            // 工作温度设置
            DeviceTempSetDto.Vo lastTempset = R.feignCheckData(deviceTempSetService.getLastOne(new DeviceTempSetDto.GetLastOneDto().setDeviceId(vo.getDeviceId())));
            vo.setJobTempSetValue(lastTempset == null ? null : lastTempset.getTempValue());
            // 设备配置
            DeviceConfigDto.Vo deviceConfig = deviceConfigService.obj(new DeviceConfigDto.Obj().setDeviceId(vo.getDeviceId())).getData();
            vo.setDeviceConfig(deviceConfig);
        }

        DeviceConfig deviceConfig = deviceConfigService.getById(obj.getDeviceId());
        vo.setTempSetInfo(BeanUtil.copyProperties(deviceConfig, DeviceInfoDto.TempSetInfo.class));
        return R.ok(vo);
    }

    @ApiOperation("小程序商户设备详情-数据统计")
    @PostMapping("dataCount")
    R<DeviceInfoDto.DeviceDataCountVO> dataCount(@RequestBody DeviceInfoDto.DeviceDataCountDTO dto) {
        dto.setMercId(MercAuthUtils.getMercId());
        return deviceInfoService.dataCount(dto);
    }

    private R checkDeviceByMerc(DeviceInfo deviceInfo) {
        Long mercId = MercAuthUtils.getMercId();
        // 商户是否已通过审核
        MercDto.Vo mercInfo = mercFeignService.obj(new MercDto.ListDTO().setId(mercId)).getData();
        if (!mercInfo.getStatus().equals(String.valueOf(MercStatus.APPROVED.getCode()))) {
            return R.fail("商户未通过审核");
        }
        // 设备是否存在
        if (!Emptys.check(deviceInfo)) {
            return R.fail("机器不存在");
        }
        // 机器是否已授权给该商户
        if (!deviceInfo.getMercId().equals(mercId)) {
            return R.fail("机器未授权给商户");
        }
        // 机器是否冻结
        Integer freezeStatus = SysDictUtils.getValue(EnumDeviceFreezeStatus.Code.CODE.getCode(), EnumDeviceFreezeStatus.N_2.getCode(), Integer.class);
        if (deviceInfo.getFreezeStatus().equals(freezeStatus)) {
            return R.fail("机器已冻结");
        }
        return R.ok();
    }

    @PostMapping("isMerc")
    @ApiOperation("判断设备是否归属商户")
    public R isMerc(@RequestBody MercMiniDeviceDto.Active active) {
        DeviceInfo deviceInfo = deviceInfoService.getById(active.getDeviceId());
        R checkR = this.checkDeviceByMerc(deviceInfo);
        if (checkR.getCode() == R.Enum.SUCCESS.getCode()) {
            Integer activeState = SysDictUtils.getValue(EnumDeviceActiveStatus.Code.CODE.getCode(), EnumDeviceActiveStatus.N_1.getCode(), Integer.class);
            String refMercCode = deviceInfo.getMercCode();
            // 非质检商户需要进行判断，质检商户跳过
            if (!"10001".equals(refMercCode) && !deviceInfo.getActiveState().equals(activeState)) {
                return R.fail("机器未激活");
            }
            return R.ok();
        }
        return checkR;
    }

    @PostMapping("getActiveInfo")
    @ApiOperation("激活设备前判断")
    public R getActiveInfo(@RequestBody MercMiniDeviceDto.Active active) {
        DeviceInfo deviceInfo = deviceInfoService.getById(active.getDeviceId());
        R checkR = this.checkDeviceByMerc(deviceInfo);
        if (checkR.getCode() == R.Enum.SUCCESS.getCode()) {
            Integer activeState = SysDictUtils.getValue(EnumDeviceActiveStatus.Code.CODE.getCode(), EnumDeviceActiveStatus.N_1.getCode(), Integer.class);
            if (deviceInfo.getActiveState().equals(activeState)) {
                return R.fail("机器已激活");
            }
            return R.ok();
        }
        return checkR;
    }

    @PostMapping("active")
    @ApiOperation("激活设备")
    public R active(@RequestBody MercMiniDeviceDto.Active2 active) {
        List<Long> deviceIds = active.getDeviceId();
        List<DeviceInfo> list = deviceInfoService.list(new LambdaQueryWrapper<DeviceInfo>()
                .in(DeviceInfo::getDeviceId, deviceIds)
        );
        JMap<Integer, DeviceInfo> cover = new JArrayList<>(list).toMap(DeviceInfo::getDeviceType).cover();
        if (cover.size() > 1) {
            return R.fail("批量激活设备类型必须一致");
        }
        for (DeviceInfo deviceInfo : list) {
            R checkR = this.checkDeviceByMerc(deviceInfo);
            if (checkR.getCode() == R.Enum.FAIL.getCode()) {
                return checkR;
            }
        }
        return FactoryUtils.getServiceRoute(DeviceFactory.class, list.get(0).getDeviceType()).active(active);
    }

    @PostMapping("restActive")
    @ApiOperation("重置设备激活")
    public R restActive(@RequestBody @Validated MercMiniDeviceDto.RestActive restActive) {
        DeviceInfoDto.Vo deviceInfo = deviceInfoService.obj(new DeviceInfoDto.Obj().setDeviceId(restActive.getDeviceId()).setIsSysinfo(true)).getData();
        DeviceSysinfoDto.Vo deviceSysinfo = deviceInfo.getDeviceSysinfo();
        if (deviceSysinfo != null) {
            restActive.setNfcSn(deviceSysinfo.getNfcSn());
        }

        return FactoryUtils.getServiceRoute(DeviceFactory.class, deviceInfo.getDeviceType()).restActive(restActive);
    }

    @ApiOperation("运营状态修改")
    @PostMapping("modifyBusyStage")
    public R modifyBusyStage(@RequestBody @Validated MercMiniDeviceDto.BusySate busySate) {
        Long mercId = MercAuthUtils.getMercId();
        DeviceInfo deviceInfo = deviceInfoService.getById(busySate.getDeviceId());
        return FactoryUtils.getServiceRoute(DeviceFactory.class, deviceInfo.getDeviceType()).busyStatus(busySate.setMercId(mercId));
    }

    @ApiOperation("修改设备信息、上传坐标等")
    @PostMapping("updateInfo")
    public R updateInfo(@RequestBody @Validated MercMiniDeviceDto.UpdateInfo dto) {
        DeviceInfo deviceInfo = deviceInfoService.getById(dto.getDeviceId());
        if (!Emptys.check(deviceInfo) || !Objects.equals(deviceInfo.getMercId(), MercAuthUtils.getMercId())) {
            return R.fail("设备不存在");
        }
        DeviceInfoDto.Update update = copy(DeviceInfoDto.Update.class, dto);
        deviceInfoService.update(update);
        return R.ok();
    }

    @ApiOperation("当前登录用户拥有的设备")
    @PostMapping("myDevices")
    R<List<Long>> myDevices() {
        return R.ok(getMyDevices());
    }

    /**
     * 获取登录人的设备
     *
     * @return
     */
    List<Long> getMyDevices() {
        boolean mercAdmin = MercAuthUtils.isMercAdmin();
        Long mercId = MercAuthUtils.getMercId();
        if (mercAdmin) {
            MercAuthUtils.MercAuth.Merc merc = MercAuthUtils.getMercAuth().getMerc();
            boolean qaModeMerc = MercAuthUtils.isQaModeMerc(merc.getMercCode());
            //非QA需要查激活的设备
            List<DeviceInfo> deviceInfos = deviceInfoService.list(Wrappers.<DeviceInfo>lambdaQuery().eq(DeviceInfo::getMercId, mercId).eq(!qaModeMerc, DeviceInfo::getActiveState, DeviceActiveStateEnum.TRUE.getCode()));
            if (CollUtil.isEmpty(deviceInfos)) {
                return CollUtil.newArrayList();
            }
            return deviceInfos.stream().map(DeviceInfo::getDeviceId).collect(Collectors.toList());
        } else {
            // 成员设备
            List<Long> deviceIds = R.feignCheckData(mercFeignService.mercUserDevice());
            return deviceIds;
        }

    }

    @PostMapping("genCode")
    @ApiOperation("蓝牙开门-生成授权码")
    public R<Boolean> genCode(@RequestBody @Validated DeviceBluetoothAuthDto.GenCode dto) {
        String deviceSn = dto.getDeviceSn();
        List<DeviceSysinfo> list = deviceSysinfoService.list(Wrappers.<DeviceSysinfo>lambdaQuery().eq(DeviceSysinfo::getDeviceSn, deviceSn).orderByDesc(DeviceSysinfo::getCreateTime));
        if (CollUtil.isEmpty(list)) {
            return R.fail("设备不存在！");
        }
        DeviceSysinfo deviceSysinfo = list.get(0);
        Long deviceId = deviceSysinfo.getDeviceId();
        // 用户输入的
        String authCode = dto.getAuthCode();
        List<Long> myDevices = getMyDevices();
        if (!myDevices.contains(deviceId)) {
            return R.fail("抱歉！您无权对此设备进行授权！");
        }
        Long mercId = MercAuthUtils.getMercId();
        DeviceBluetoothAuth deviceBluetoothAuth = deviceBluetoothAuthService.getOne(Wrappers.<DeviceBluetoothAuth>lambdaQuery()
                .eq(DeviceBluetoothAuth::getDeviceId, deviceId)
                .eq(DeviceBluetoothAuth::getMercId, mercId)
                .eq(DeviceBluetoothAuth::getUseStatus, DeviceAuthCodeUseStatus.UN_USED.getCode())
        );
        String cacheAuthCode = getCacheAuthCode(deviceId);
        if (deviceBluetoothAuth != null) {
            if (StrUtil.isNotEmpty(cacheAuthCode)) {
                return R.fail("此设备尚有未使用的授权码：【" + cacheAuthCode + "】,请使用后再来生成！");
            } else {
                // 已失效了
                deviceBluetoothAuthService.saveOrUpdate(deviceBluetoothAuth.setUseStatus(DeviceAuthCodeUseStatus.TIME_OUT.getCode()));
            }

        }


        // 缓存
        setCacheAuthCode(deviceId, authCode);
        DeviceBluetoothAuth saveInfo = new DeviceBluetoothAuth()
                .setDeviceId(deviceId)
                .setMercId(mercId)
                .setDeviceId(deviceId).setAuthCode(authCode);
        return R.ok(deviceBluetoothAuthService.save(saveInfo));
    }

    @PostMapping("genCodeByAdmin")
    @ApiOperation("蓝牙开门-平台管理员生成授权码（通用码）")
    public R<Long> genCodeByAdmin(@RequestBody @Validated DeviceBluetoothAuthDto.GenCodeByAdmin dto) {

        long deviceId = YitIdHelper.nextId();

        // 缓存
        setCacheAuthCode(deviceId, String.valueOf(deviceId));
        DeviceBluetoothAuth saveInfo = new DeviceBluetoothAuth()
                .setDeviceId(deviceId)
                .setMercId(0L)
                .setDeviceId(deviceId).setAuthCode(String.valueOf(deviceId));
        deviceBluetoothAuthService.save(saveInfo);
        return R.ok(deviceId);
    }

    @PostMapping("verificationBlueCode")
    @ApiOperation("蓝牙开门-校验并使用授权码(平台管理员生成)")
    public R<Boolean> verificationBlueCode(@RequestBody @Validated DeviceBluetoothAuthDto.VerificationCodeByAdmin dto) {
        String authCode = dto.getAuthCode();
        String cacheAuthCode = getCacheAuthCode(Long.valueOf(authCode));
        if (!authCode.equals(cacheAuthCode)) {
            return R.fail("您输入的授权码有误或者无效！");
        }
        // 验证通过，缓存去掉授权码，并更新状态
//        Long mercId = MercAuthUtils.getMercId();
        DeviceBluetoothAuth deviceBluetoothAuth = deviceBluetoothAuthService.getOne(Wrappers.<DeviceBluetoothAuth>lambdaQuery()
                        .eq(DeviceBluetoothAuth::getDeviceId, Long.valueOf(authCode))
                        .eq(DeviceBluetoothAuth::getAuthCode, authCode)
                        .eq(DeviceBluetoothAuth::getUseStatus, DeviceAuthCodeUseStatus.UN_USED.getCode())
        );
        if (deviceBluetoothAuth == null) {
            return R.fail("您输入的授权码无效！");
        }
        // 缓存去掉授权码
        delCacheAuthCode(Long.valueOf(authCode));
        deviceBluetoothAuth.setUseStatus(DeviceAuthCodeUseStatus.USED.getCode());
        deviceBluetoothAuth.setUseUser(AuthorizeUtils.getLoginId(Long.class));
        deviceBluetoothAuth.setUseTime(LocalDateTime.now());
        return R.ok(deviceBluetoothAuthService.saveOrUpdate(deviceBluetoothAuth));
    }



    @PostMapping("verificationCode")
    @ApiOperation("蓝牙开门-校验并使用授权码")
    public R<Boolean> verificationCode(@RequestBody @Validated DeviceBluetoothAuthDto.VerificationCode dto) {
        log.info("蓝牙开门-校验并使用授权码：" + JSONUtil.toJsonPrettyStr(dto));
        String deviceSn = dto.getDeviceSn();
        List<DeviceSysinfo> list = deviceSysinfoService.list(Wrappers.<DeviceSysinfo>lambdaQuery().eq(DeviceSysinfo::getDeviceSn, deviceSn).orderByDesc(DeviceSysinfo::getCreateTime));
        if (CollUtil.isEmpty(list)) {
            return R.fail("设备不存在！");
        }
        DeviceSysinfo deviceSysinfo = list.get(0);
        Long deviceId = deviceSysinfo.getDeviceId();
        String authCode = dto.getAuthCode();
        String cacheAuthCode = getCacheAuthCode(deviceId);
        if (!authCode.equals(cacheAuthCode)) {
            return R.fail("您输入的授权码有误或者无效！");
        }
        // 验证通过，缓存去掉授权码，并更新状态
//        Long mercId = MercAuthUtils.getMercId();
        DeviceBluetoothAuth deviceBluetoothAuth = deviceBluetoothAuthService.getOne(Wrappers.<DeviceBluetoothAuth>lambdaQuery()
                        .eq(DeviceBluetoothAuth::getDeviceId, deviceId)
                        .eq(DeviceBluetoothAuth::getAuthCode, authCode)
//                .eq(DeviceBluetoothAuth::getMercId, mercId)
                        .eq(DeviceBluetoothAuth::getUseStatus, DeviceAuthCodeUseStatus.UN_USED.getCode())
        );
        if (deviceBluetoothAuth == null) {
            return R.fail("您输入的授权码无效！");
        }
        // 缓存去掉授权码
        delCacheAuthCode(deviceId);
        deviceBluetoothAuth.setUseStatus(DeviceAuthCodeUseStatus.USED.getCode());
        deviceBluetoothAuth.setUseUser(AuthorizeUtils.getLoginId(Long.class));
        deviceBluetoothAuth.setUseTime(LocalDateTime.now());
        return R.ok(deviceBluetoothAuthService.saveOrUpdate(deviceBluetoothAuth));
    }


    @ApiOperation("支付宝Npad音量设置")
    @PostMapping("setAliNpadVol")
    public R<Boolean> setAliNpadVol(@RequestBody @Validated DeviceInfoDto.NfcVol nfcVol) {
        String deviceId = nfcVol.getDeviceId();
        DeviceSetAttr dto = new DeviceSetAttr();
        dto.setType("VOL").setTerminalId(deviceId).setValue(nfcVol.getValue());
        return R.ok(R.feignCheckData(alipayDeviceService.setAttributes(dto)));
    }


    @ApiOperation("音量、温度查询")
    @PostMapping("queryAliNpadVol")
    public R<Boolean> queryAliNpadVol(@RequestBody DeviceInfoDto.NfcVolQuery dto) {
        DeviceQueryAttr deviceQueryAttr = new DeviceQueryAttr();
        deviceQueryAttr.setTerminalId(dto.getDeviceId());
        deviceQueryAttr.setType("VOL");
        return R.ok(R.feignCheckData(alipayDeviceService.queryAttributes(deviceQueryAttr)));
    }

}
