package cn.iocoder.yudao.module.member.service.diningplates;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.websocket.core.sender.WebSocketMessageSender;
import cn.iocoder.yudao.module.member.controller.admin.diningplates.vo.DiningPlatesPageReqVO;
import cn.iocoder.yudao.module.member.controller.admin.diningplates.vo.DiningPlatesSaveReqVO;
import cn.iocoder.yudao.module.member.controller.admin.diningplates.vo.DiningPlatesStoreVO;
import cn.iocoder.yudao.module.member.controller.app.diningplates.vo.AppUserInfo;
import cn.iocoder.yudao.module.member.controller.app.user.vo.AppUserInfoCardVO;
import cn.iocoder.yudao.module.member.dal.dataobject.admincard.AdminCardDO;
import cn.iocoder.yudao.module.member.dal.dataobject.diningplates.DiningPlatesDO;
import cn.iocoder.yudao.module.member.dal.dataobject.order.DishOrderDO;
import cn.iocoder.yudao.module.member.dal.dataobject.storediningplates.StoreDiningPlatesDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.diningplates.DiningPlatesMapper;
import cn.iocoder.yudao.module.member.dal.mysql.order.DishOrderMapper;
import cn.iocoder.yudao.module.member.dal.mysql.user.MemberUserMapper;
import cn.iocoder.yudao.module.member.enums.GroupTypeEnum;
import cn.iocoder.yudao.module.member.service.admincard.AdminCardService;
import cn.iocoder.yudao.module.member.service.amount.DeductionService;
import cn.iocoder.yudao.module.member.service.async.MemberAsyncService;
import cn.iocoder.yudao.module.member.service.group.MemberGroupService;
import cn.iocoder.yudao.module.member.service.holiday.HolidayService;
import cn.iocoder.yudao.module.member.service.storediningplates.StoreDiningPlatesService;
import cn.iocoder.yudao.module.member.util.MemberConstants;
import cn.iocoder.yudao.module.system.api.carteen.CarteenApi;
import cn.iocoder.yudao.module.system.api.carteen.dto.CarteenRespDto;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
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.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;

/**
 * 餐盘 Service 实现类
 *
 * @author 开发账号
 */
@Service
@Validated
public class DiningPlatesServiceImpl implements DiningPlatesService {

    @Resource
    private DiningPlatesMapper diningPlatesMapper;
    @Resource
    private MemberUserMapper memberUserMapper;
    @Resource
    private DishOrderMapper dishOrderMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private WebSocketMessageSender webSocketMessageSender;
    @Resource
    private CarteenApi carteenApi;
    @Resource
    private AdminCardService adminCardService;
    @Resource
    private MemberAsyncService asyncService;
    @Resource
    private DeductionService deductionService;
    @Resource
    private StoreDiningPlatesService storeDiningPlatesService;
    @Resource
    private MemberGroupService memberGroupService;
    @Resource
    private HolidayService holidayService;

    @Override
    public Long createDiningPlates(DiningPlatesSaveReqVO createReqVO) {
        // 插入
        DiningPlatesDO diningPlates = BeanUtils.toBean(createReqVO, DiningPlatesDO.class);
        List<DiningPlatesDO> diningPlatesDOS = diningPlatesMapper.selectList(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlates.getDiningPlatesNum())
                .eq(DiningPlatesDO::getStoreId, diningPlates.getStoreId()));
        if(CollectionUtil.isNotEmpty(diningPlatesDOS)){
            throw exception(DINING_PLATES_ALREADY);
        }
        diningPlatesMapper.insert(diningPlates);
        // 返回
        return diningPlates.getId();
    }

    @Override
    public void insertDiningPlates(DiningPlatesDO diningPlatesDO) {
        diningPlatesMapper.insert(diningPlatesDO);
    }

    @Override
    public void updateDiningPlates(DiningPlatesSaveReqVO updateReqVO) {
        // 校验存在
        validateDiningPlatesExists(updateReqVO.getId());
        // 更新
        DiningPlatesDO updateObj = BeanUtils.toBean(updateReqVO, DiningPlatesDO.class);
        diningPlatesMapper.updateById(updateObj);
    }

    @Override
    public void deleteDiningPlates(Long id) {
        // 校验存在
        validateDiningPlatesExists(id);
        // 删除
        diningPlatesMapper.deleteById(id);
    }

    private void validateDiningPlatesExists(Long id) {
        if (diningPlatesMapper.selectById(id) == null) {
            throw exception(DINING_PLATES_NOT_EXISTS);
        }
    }

    @Override
    public DiningPlatesDO getDiningPlates(Long id) {
        return diningPlatesMapper.selectById(id);
    }

    @Override
    public DiningPlatesDO getDiningPlatesByNum(String diningPlatesNum,Long storeId) {
        LambdaQueryWrapper<DiningPlatesDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId, storeId);
        List<DiningPlatesDO> list = diningPlatesMapper.selectList(wrapper);
        if(CollectionUtil.isNotEmpty(list)){
            return list.get(0);
        }
        return new DiningPlatesDO();
    }

    @Override
    public PageResult<DiningPlatesDO> getDiningPlatesPage(DiningPlatesPageReqVO pageReqVO) {
        PageResult<DiningPlatesDO> diningPlatesDOPageResult = diningPlatesMapper.selectPage(pageReqVO);
        List<DiningPlatesDO> list = diningPlatesDOPageResult.getList();
        if(CollectionUtil.isNotEmpty(list)){
            list.forEach(diningPlatesDO -> {
                diningPlatesDO.setStoreName(carteenApi.getCarteenById(diningPlatesDO.getStoreId()).getStoresName());
            });
        }
        return diningPlatesDOPageResult;
    }

    @Override
    public Map<String, List<DiningPlatesDO>> getDiningPlatesToCharging(Integer time, Integer abnormalTime) {
        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now();

        // 计算指定分钟之前的时间
        LocalDateTime normalTimeAgo = currentTime.minusMinutes(time);

        LocalDateTime abnormalTimeAgo = currentTime.minusMinutes(abnormalTime);

        LambdaQueryWrapper<DiningPlatesDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DiningPlatesDO::getStatus, DiningPlatesDO.USE)
                .eq(DiningPlatesDO::getPayFlag, DiningPlatesDO.TO_PAY)
                .le(DiningPlatesDO::getBindingTime, normalTimeAgo);
        List<DiningPlatesDO> diningPlatesDOS = diningPlatesMapper.selectList(wrapper);
        Map<String, List<DiningPlatesDO>> map = new HashMap<>();
        // 筛选正常结算的订单
        List<DiningPlatesDO> normalList = diningPlatesDOS.stream().filter(dp -> dp.getUserId() != null).collect(Collectors.toList());
        map.put("normal",normalList);
        List<DiningPlatesDO> abnormalList = diningPlatesDOS.stream().filter(dp -> dp.getUserId() == null && !dp.getBindingTime().isAfter(abnormalTimeAgo)).collect(Collectors.toList());
        map.put("abnormal",abnormalList);
        return map;
    }

    @Override
    public void updatePayFlag(List<Long> ids, String payStatus) {
        diningPlatesMapper.update(Wrappers.<DiningPlatesDO>lambdaUpdate()
                .set(DiningPlatesDO::getPayFlag, DiningPlatesDO.PAY)
                .in(DiningPlatesDO::getId, ids));
    }

    @Override
    public void updateBind(List<Long> ids) {
        diningPlatesMapper.update(Wrappers.<DiningPlatesDO>lambdaUpdate()
                .set(DiningPlatesDO::getPayFlag, DiningPlatesDO.TO_PAY)
                .set(DiningPlatesDO::getStatus, DiningPlatesDO.FREE)
                .set(DiningPlatesDO::getUserId, null)
                .set(DiningPlatesDO::getBindingTime, null)
                .set(DiningPlatesDO::getOrderId, null)
                .in(DiningPlatesDO::getId, ids));
    }

    @Override
    public List<DiningPlatesDO> getDiningPlatesList() {
        return diningPlatesMapper.selectList();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AppUserInfoCardVO bind(String diningPlatesNum, String cardId,Long storeId) {
        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId,storeId)
                .last(MemberConstants.LIMIT_ONE));
        checkDiningPlates(diningPlatesDO);
        MemberUserDO memberUserDO = memberUserMapper.selectOne(Wrappers.<MemberUserDO>lambdaQuery()
                .eq(MemberUserDO::getCardId, cardId)
                .last(MemberConstants.LIMIT_ONE));
        checkMemberUser(memberUserDO, false);
        //订单验证
        checkOrder(memberUserDO.getId(),diningPlatesDO.getStoreId());

        //余额验证
        BigDecimal money = checkMoney(memberUserDO, storeId,true);

        //group验证
        checkGroup(memberUserDO.getId(),storeId);

        diningPlatesDO.setUserId(memberUserDO.getId());

        //创建初始订单
        DishOrderDO dishOrderDO = new DishOrderDO();
        if(diningPlatesDO.getOrderId()==null){
            diningPlatesDO.setStatus(DiningPlatesDO.USE);
            diningPlatesDO.setBindingTime(LocalDateTime.now());

            dishOrderDO.setDiningPlatesNum(diningPlatesNum)
                    .setOrderStatus(DishOrderDO.INCOMPLETE)
                    .setUserId(memberUserDO.getId())
                    .setStoreId(storeId);
            dishOrderMapper.insert(dishOrderDO);
            diningPlatesDO.setOrderId(dishOrderDO.getId());
            //设置总价
            stringRedisTemplate.opsForValue().set(diningPlatesNum+"-"+storeId, "0");
        }else{
            dishOrderDO.setId(diningPlatesDO.getOrderId());
            dishOrderDO.setUserId(memberUserDO.getId());
            dishOrderDO.setOrderStatus(DishOrderDO.INCOMPLETE);
            dishOrderMapper.updateById(dishOrderDO);
        }
        diningPlatesMapper.updateById(diningPlatesDO);
        AppUserInfoCardVO data = new AppUserInfoCardVO();
        data.setName(StrUtil.isNotBlank(memberUserDO.getName())?memberUserDO.getName():memberUserDO.getNickname());
        data.setMoney(money);

        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AppUserInfoCardVO bindByFace(String diningPlatesNum, Long faceId, Long storeId, String mobile,String faceData) {
        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId,storeId)
                .last(MemberConstants.LIMIT_ONE));
        checkDiningPlates(diningPlatesDO);

        LambdaQueryWrapper<MemberUserDO> wrapper = new LambdaQueryWrapper<>();
        if(faceId!=null){
            wrapper.eq(MemberUserDO::getFaceId, faceId);
        }
        if(StrUtil.isNotBlank(mobile) && faceId==null){
            wrapper.eq(MemberUserDO::getMobile, mobile);
        }
        wrapper.last(MemberConstants.LIMIT_ONE);
        MemberUserDO memberUserDO = memberUserMapper.selectOne(wrapper);
        checkMemberUser(memberUserDO, true);
        //订单验证
        checkOrder(memberUserDO.getId(),diningPlatesDO.getStoreId());
        //余额验证
        BigDecimal money = checkMoney(memberUserDO,storeId,false);
        //group验证
        checkGroup(memberUserDO.getId(),storeId);

        diningPlatesDO.setUserId(memberUserDO.getId());
        //创建初始订单
        String faceUrl = "facedata/orderFaceData/"+ IdUtil.getSnowflakeNextIdStr() +".jpg";
        DishOrderDO dishOrderDO = new DishOrderDO();
        if(diningPlatesDO.getOrderId()==null){
            diningPlatesDO.setStatus(DiningPlatesDO.USE);
            diningPlatesDO.setBindingTime(LocalDateTime.now());
            dishOrderDO.setDiningPlatesNum(diningPlatesNum)
                    .setOrderStatus(DishOrderDO.INCOMPLETE)
                    .setUserId(memberUserDO.getId())
                    .setStoreId(storeId)
                    .setFaceData(faceUrl)
            ;
            dishOrderMapper.insert(dishOrderDO);
            diningPlatesDO.setOrderId(dishOrderDO.getId());
            //设置总价
            stringRedisTemplate.opsForValue().set(diningPlatesNum+"-"+storeId, "0");
        }else{
            dishOrderDO.setId(diningPlatesDO.getOrderId());
            dishOrderDO.setUserId(memberUserDO.getId());
            dishOrderDO.setOrderStatus(DishOrderDO.INCOMPLETE);
            dishOrderDO.setFaceData(faceUrl);
            dishOrderMapper.updateById(dishOrderDO);
        }
//        asyncService.saveFace(faceData,faceUrl);

        diningPlatesMapper.updateById(diningPlatesDO);
        AppUserInfoCardVO data = new AppUserInfoCardVO();
        data.setName(StrUtil.isNotBlank(memberUserDO.getName())?memberUserDO.getName():memberUserDO.getNickname());
        data.setMoney(money);

        return data;
    }

    @Override
    public Boolean checkBind(String diningPlatesNum, Long storeId) {
        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId,storeId)
                .last(MemberConstants.LIMIT_ONE));
        if (diningPlatesDO == null || diningPlatesDO.getUserId() == null) {
            return false;
        }
        //刷新绑定时间
        //diningPlatesDO.setBindingTime(LocalDateTime.now());
        //diningPlatesMapper.updateById(diningPlatesDO);
        return true;
    }

    @Override
    public AppUserInfoCardVO appCheckBind(String diningPlatesNum, Long storeId) {

        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId,storeId)
                .last(MemberConstants.LIMIT_ONE));

        if (diningPlatesDO == null) {
            throw exception(DINING_PLATES_NOT_EXISTS);
        }
        //刷新绑定时间
        asyncService.flashTime(diningPlatesDO);

        if (  diningPlatesDO.getUserId() == null ) {
            throw exception(DINING_PLATES_NOT_BIND);
        }

        AppUserInfoCardVO appUserInfoCardVO = new AppUserInfoCardVO();

        String redisKey = "USER_"+diningPlatesDO.getUserId();
        String s = stringRedisTemplate.opsForValue().get(redisKey);
        if(StrUtil.isNotBlank(s)){
            appUserInfoCardVO = JSONUtil.toBean(s, AppUserInfoCardVO.class);

        }else {
            MemberUserDO memberUserDO = memberUserMapper.selectById(diningPlatesDO.getUserId());
            appUserInfoCardVO.setName(memberUserDO.getNickname());
            appUserInfoCardVO.setMoney(memberUserDO.getMoney());
            stringRedisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(appUserInfoCardVO));
        }
        return appUserInfoCardVO;
    }

    public void checkDiningPlates(DiningPlatesDO diningPlatesDO) {
        if (diningPlatesDO == null) {
            throw exception(DINING_PLATES_NOT_EXISTS);
        }
        if (diningPlatesDO.getUserId() != null) {
            throw exception(DINING_PLATES_ALREADY_BIND);
        }
        List<AdminCardDO> adminCardList = adminCardService.getAdminCardList();
        if(CollectionUtil.isNotEmpty(adminCardList)){
            List<String> collect = adminCardList.stream().map(AdminCardDO::getCardNo).collect(Collectors.toList());
            if(collect.contains(diningPlatesDO.getDiningPlatesNum())){
                throw exception(ADMIN_CARD);
            }
        }


    }

    public void checkMemberUser(MemberUserDO memberUserDo, Boolean isFace) {
        if (memberUserDo == null) {
            if (isFace) {
                throw exception(FACE_NOT_BIND_USER);
            } else {
                throw exception(CARD_NOT_BIND_USER);
            }
        }
        //if (StrUtil.isBlank(memberUserDo.getCardId())) {
        //    throw exception(CARD_NOT_BIND);
        //}
    }

    public BigDecimal checkMoney(MemberUserDO memberUserDO,Long storeId,boolean isCard) {
        //获取所有现金
        BigDecimal cashAmount = memberUserDO.getCashAmount();
        
        boolean typeHoliday = false;
        if(MemberConstants.LIMIT_SWITCH){
            //获取用户所在组分类
            List<Integer> types = memberGroupService.getGroupTypeListByUserId(memberUserDO.getId());
            //查询今天是否假期
            Boolean isHoliday = holidayService.checkHoliday();
            typeHoliday = isHoliday && (types.contains(GroupTypeEnum.ADMINISTRATIVE.getCode()) || types.contains(GroupTypeEnum.DISTRICT.getCode()));
            if(typeHoliday){
                cashAmount = BigDecimal.ZERO;
            }
        }

        BigDecimal money = memberUserDO.getWxAmount().add(cashAmount);
        BigDecimal compareMoney = carteenApi.getCarteenById(storeId).getBindMoney();
        if (money.compareTo(compareMoney) < 0) {
            if(typeHoliday){
                throw exception(INSUFFICIENT_BALANCE_NEW);
            }
            throw exception(INSUFFICIENT_BALANCE);
        }

        //餐盘个数验证
        boolean applyToCard = isCard && memberUserDO.getReception() == 1;
        StoreDiningPlatesDO byAmount = storeDiningPlatesService.getByAmount(money, storeId, applyToCard);
        if(byAmount != null){
            Integer checkNum = byAmount.getNum();
            Integer num = getDiningPlatesByUserId(memberUserDO.getId(), storeId);
            if(num >= checkNum){
                throw exception(DINING_PLATES_BIND_MAX);
            }
        }

        return money;
    }

    public void checkOrder(Long userId,Long carteenId) {

        LambdaQueryWrapper<DishOrderDO> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DishOrderDO::getUserId,userId);
        wrapper.eq(DishOrderDO::getOrderStatus,DishOrderDO.TOCOMPLETE);
        wrapper.eq(DishOrderDO::getStoreId,carteenId);
        List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList(wrapper);
        ErrorCode code = new ErrorCode(1_004_099_008, "存在未支付完的订单");
        if(CollectionUtil.isNotEmpty(dishOrderDOS)){
            throw exception(code);
        }
    }

    public void checkGroup(Long userId,Long canteenId){

        Boolean b = memberGroupService.judgeGroup(userId, canteenId);
        if(b){
            throw exception(new ErrorCode(1_004_099_008, "不能在当前店消费"));
        }
    }


    public Integer getDiningPlatesByUserId(Long userId,Long storeId){
        return diningPlatesMapper.selectCount(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getUserId, userId).eq(DiningPlatesDO::getStoreId,storeId)).intValue();
    }



    @Override
    public List<DiningPlatesStoreVO> getDiningPlatesNum(LocalDateTime localDateTime, Integer time) {
        List<DiningPlatesStoreVO> result  = new ArrayList<>();
        // 获取当前时间
        LocalDateTime endTime = localDateTime;

        // 计算指定分钟之前的时间
        LocalDateTime startTime = endTime.minusMinutes(10);

        List<DiningPlatesDO> diningPlatesDOS = diningPlatesMapper.selectList(Wrappers.<DiningPlatesDO>lambdaQuery()
                .le(DiningPlatesDO::getBindingTime, endTime)
                .gt(DiningPlatesDO::getBindingTime, startTime));
        List<CarteenRespDto> carteenList = carteenApi.getCarteenList();
        carteenList.forEach(dto->{
            DiningPlatesStoreVO diningPlatesStoreVO = new DiningPlatesStoreVO();
            diningPlatesStoreVO.setStoreId(dto.getId());
            diningPlatesStoreVO.setStoreName(dto.getStoresName());
            long count = diningPlatesDOS.stream().filter(diningPlatesDO -> dto.getId().equals(diningPlatesDO.getStoreId())).count();
            diningPlatesStoreVO.setNum(Integer.valueOf(String.valueOf(count)));
            result.add(diningPlatesStoreVO);
        });
        return result;
    }

    /**
     * 绑定之后的操作
     */
    public void afterBind(Long userId) {
        //判断是否已记录
        LocalDate today = LocalDate.now();

        // 一天的开始时间
        LocalDateTime startOfDay = today.atStartOfDay();
        // 一天的结束时间
        LocalDateTime endOfDay = today.atTime(LocalTime.MAX);

        List<DishOrderDO> dishOrderDOS = dishOrderMapper.selectList(Wrappers.<DishOrderDO>lambdaQuery()
                .eq(DishOrderDO::getUserId, userId)
                .between(DishOrderDO::getCreateTime, startOfDay, endOfDay));
        if (dishOrderDOS.size() > 0) {
            return;
        }

        String s = stringRedisTemplate.opsForValue().get(MemberConstants.CUSTOMER_PREFIX);
        if (StrUtil.isBlank(s)) {
            s = "1";
        } else {
            s = String.valueOf(Integer.valueOf(s) + 1);
        }
        stringRedisTemplate.opsForValue().set(MemberConstants.CUSTOMER_PREFIX, s);
        //根据餐盘对应的门店ID发送给对应的用户
        webSocketMessageSender.sendObject(UserTypeEnum.ADMIN.getValue(), 1L, // 给指定用户
                "demo-message-receive", s);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void unbind(String diningPlatesNum,Long storeId) {

        String money = stringRedisTemplate.opsForValue().get(diningPlatesNum+"-"+storeId);
        if(StringUtils.isBlank(money)){
            throw exception(DINING_PLATES_NOT_BIND);
        }

        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId,storeId)
                .last("limit 1"));

        if(!"0".equals(money)){
            DishOrderDO dishOrderDO = dishOrderMapper.selectById(diningPlatesDO.getOrderId());
            deductionService.deduction(dishOrderDO);
            dishOrderMapper.updateById(dishOrderDO);
        }else {
            dishOrderMapper.deleteById(diningPlatesDO.getOrderId());
        }
        diningPlatesMapper.update(Wrappers.<DiningPlatesDO>lambdaUpdate()
                .set(DiningPlatesDO::getPayFlag, DiningPlatesDO.TO_PAY)
                .set(DiningPlatesDO::getStatus, DiningPlatesDO.FREE)
                .set(DiningPlatesDO::getUserId, null)
                .set(DiningPlatesDO::getBindingTime, null)
                .set(DiningPlatesDO::getOrderId, null)
                .eq(DiningPlatesDO::getId,diningPlatesDO.getId()));
    }

    @Override
    public AppUserInfo getMoney(String diningPlatesNum,Long dishId,Long storeId) {
        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId,storeId)
                .last("limit 1"));
        MemberUserDO memberUserDO = memberUserMapper.selectById(diningPlatesDO.getUserId());

        AppUserInfo appUserInfo = new AppUserInfo();
        appUserInfo.setNickname(StrUtil.isNotBlank(memberUserDO.getName())?memberUserDO.getName():memberUserDO.getNickname())
                .setMoney(memberUserDO.getMoney())
                .setOrderMoney(Optional.ofNullable(stringRedisTemplate.opsForValue().get(diningPlatesNum + "-" + storeId)).map(BigDecimal::new).orElse(BigDecimal.ZERO))
                .setReception(memberUserDO.getReception()).setLimitAmount(memberUserDO.getLimitAmount());
        return appUserInfo;
    }

    @Override
    public List<String> getBindDiningPlatesList() {
        List<DiningPlatesDO> diningPlatesDOS = diningPlatesMapper.selectList(Wrappers.<DiningPlatesDO>lambdaQuery()
                .isNotNull(DiningPlatesDO::getUserId));
        List<String> list = diningPlatesDOS.stream().map(DiningPlatesDO::getDiningPlatesNum).collect(Collectors.toList());
        return list;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, String> checkBindAndUnBind(String diningPlatesNum,Long storeId) {

        Map<String, String> map = new HashMap<>();

        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getDiningPlatesNum, diningPlatesNum)
                .eq(DiningPlatesDO::getStoreId, storeId));
        if(diningPlatesDO == null ) {
            map.put("data", "absent");
            map.put("msg",null);
        }else if (diningPlatesDO.getUserId() == null){
            map.put("data", "unbind");
            map.put("msg",null);
        }else {
            if (diningPlatesDO.getBindingTime()!=null){
                LocalDateTime bindingTime = diningPlatesDO.getBindingTime();
                long seconds = Duration.between(bindingTime, LocalDateTime.now()).getSeconds();
                if(seconds <=3){
                    throw exception(DINING_PLATES_TIME);
                }
            }
            unbind(diningPlatesNum,storeId);
            map.put("data", "bind");
            map.put("msg","餐盘已解绑");
        }

        return map;
    }

    @Override
    public BigDecimal getOrderMoney(Long orderId) {
        DiningPlatesDO diningPlatesDO = diningPlatesMapper.selectOne(Wrappers.<DiningPlatesDO>lambdaQuery()
                .eq(DiningPlatesDO::getOrderId, orderId));
        String s = stringRedisTemplate.opsForValue().get(diningPlatesDO.getDiningPlatesNum() + "-" + diningPlatesDO.getStoreId());
        return StrUtil.isNotBlank(s)?new BigDecimal(s):null;
    }

    @Override
    public void updateById(DiningPlatesDO diningPlatesDO) {
        diningPlatesMapper.updateById(diningPlatesDO);
    }
}