package com.kxs.store.biz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kxs.common.core.constant.CommonConstants;
import com.kxs.common.core.constant.SecurityConstants;
import com.kxs.common.core.constant.enums.*;
import com.kxs.common.core.exception.GlobalCustomerException;
import com.kxs.common.core.util.R;
import com.kxs.common.core.util.RetOps;
import com.kxs.common.security.util.SecurityUtils;
import com.kxs.product.api.feign.RemoteKxsProductService;
import com.kxs.product.api.model.KxsBrand;
import com.kxs.product.api.model.KxsMachine;
import com.kxs.product.api.model.KxsMachineCirculationLog;
import com.kxs.product.api.model.KxsTicket;
import com.kxs.store.api.dto.kxsapp.storeOrder.ApplyMachineDTO;
import com.kxs.store.api.dto.kxsapp.storeOrder.StoreOrderListDTO;
import com.kxs.store.api.dto.kxsapp.storeOrder.StoreOrderTransferUserDTO;
import com.kxs.store.api.model.*;
import com.kxs.store.api.vo.kxsapp.storeOrder.StoreOrderDetailVO;
import com.kxs.store.api.vo.kxsapp.storeOrder.StoreOrderListVO;
import com.kxs.store.api.vo.kxsapp.userOrder.UserApplyMachineDetailVO;
import com.kxs.store.api.vo.kxsapp.userOrder.UserApplyMahineListVO;
import com.kxs.store.biz.constant.StoreConstants;
import com.kxs.store.biz.constant.enums.*;
import com.kxs.store.biz.mapper.*;
import com.kxs.store.biz.service.*;
import com.kxs.system.api.feign.RemoteUserMsgService;
import com.kxs.system.api.model.KxsUserMsg;
import com.kxs.system.api.util.MsgTemplateUtil;
import com.kxs.system.api.util.ParamResolver;
import com.kxs.user.api.feign.RemoteKxsUserService;
import com.kxs.user.api.model.KxsUser;
import com.kxs.user.api.model.KxsUserAdvance;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 客小爽机具申请表(KxsMachineApply)表服务实现类
 *
 * @author 系统
 * @since 2024-01-08 09:46:02
 */
@Service("kxsMachineApplyService")
@RequiredArgsConstructor
@Slf4j
public class KxsMachineApplyServiceImpl extends ServiceImpl<KxsMachineApplyMapper, KxsMachineApply> implements KxsMachineApplyService {

    private final KxsMachineApplyDetailMapper kxsMachineApplyDetailMapper;

    private final KxsMachineAdvanceInfoMapper kxsMachineAdvanceInfoMapper;

    private final KxsWarehouseLimitService kxsWarehouseLimitService;

    private final KxsWarehouseStockService kxsWarehouseStockService;

    private final KxsWarehouseStockLogService kxsWarehouseStockLogService;

    private final KxsWarehouseMapper kxsWarehouseMapper;

    private final RemoteKxsProductService remoteKxsProductService;

    private final RemoteKxsUserService remoteKxsUserService;

    private final RemoteUserMsgService remoteUserMsgService;

    private final KxsSendTotalService kxsSendTotalService;

    @Override
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public R applyMachine(ApplyMachineDTO param) {

        Long userId = SecurityUtils.getUser().getId();
        //订单号
        Snowflake snowflake = IdUtil.getSnowflake(1, userId);
        long orderSn = snowflake.nextId();

        KxsMachineApply order = new KxsMachineApply();
        BeanUtils.copyProperties(param, order);
        order.setOrderSn("BA" + orderSn);
        //查询申请用户
        R<KxsUser> userResult = remoteKxsUserService.loadUserById(userId.intValue(), SecurityConstants.FROM_IN);
        KxsUser user = RetOps.of(userResult)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
        order.setUserId(userId.intValue());
        order.setUsername(user.getUsername());
        order.setUserCode(user.getUserCode());
        //预发机申请
        if(param.getIsAdvance() == 1){
            order.setStatus(MachineOrderStatusEnum.APPLY_SUCCESSFUL.getType());
        }
        //查询品牌
        R<KxsBrand> kxsBrandR = remoteKxsProductService.loadByBrand(param.getBrandId(), SecurityConstants.FROM_IN);
        KxsBrand brand = RetOps.of(kxsBrandR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription()));
        order.setBrandName(brand.getName());
        //添加订单
        baseMapper.insert(order);

        List<String> snList = param.getSnList();
        //预发机
        List<String> advanceList = param.getAdvanceList();
        for (int i = 0; i < snList.size(); i++) {

            String sn = snList.get(i);
            //新增订单详情
            KxsMachineApplyDetail orderDetail = new KxsMachineApplyDetail();
            orderDetail.setOrderId(order.getId());
            orderDetail.setApplyType(param.getApplyType());
            //循环结束时间
            LocalDateTime recycleEndTime = null;
            //兑换券申请
            if (param.getApplyType().equals(MachineOrderEnum.M_TYPE_SN.getType())){
                //查询券码
                R<KxsTicket> ticketResult = remoteKxsProductService.loadTicketBySn(sn, SecurityConstants.FROM_IN);
                KxsTicket ticket = RetOps.of(ticketResult)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.TICKET_NOT_FIND.getDescription()));

                //券码被使用返回错误
                if(!ticket.getStatus().equals(TicketStatusEnum.TICKET_UNUSED.getType())){
                    throw new GlobalCustomerException(StoreErrorTypeEnum.TICKET_CODE_UN.getDescription());
                }
                //冻结券码,发货后 驳回改回未使用 通过修改为已使用
                ticket.setStatus(TicketStatusEnum.TICKET_FREEZE.getType());
                R<Boolean> result = remoteKxsProductService.updateByTicket(ticket, SecurityConstants.FROM_IN);
                if(!result.getData()){
                    throw new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription());
                }
                orderDetail.setTicketId(ticket.getId());
                orderDetail.setTicketCode(sn);
            }
            //循环机申请
            else{
                R<KxsMachine> machineResult = remoteKxsProductService.loadMachineBySn(sn, SecurityConstants.FROM_IN);
                KxsMachine machine = RetOps.of(machineResult)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));

                //判断状态
                if (machine.getRecycleStatus().equals(MachineRecycleStatusEnum.UN_RECYCLE_STATUS.getType())) {
                    throw new GlobalCustomerException(StoreErrorTypeEnum.UN_RECYCLE_STATUS.getDescription());
                }

                //修改机具循环状态
                machine.setRecycleStatus(MachineRecycleStatusEnum.UN_RECYCLE_STATUS.getType());
                R<Boolean> result = remoteKxsProductService.updateByMachine(machine, SecurityConstants.FROM_IN);
                if(!result.getData()){
                    throw new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription());
                }
                recycleEndTime = machine.getRecycleEndTime();
                orderDetail.setRecycleMachineId(machine.getId());
            }

            //预发机申请
            if(param.getIsAdvance() == 1){
                String advanceSn = advanceList.get(i);
                //查询机具
                R<KxsMachine> machineResult = remoteKxsProductService.loadMachineBySn(advanceSn, SecurityConstants.FROM_IN);
                KxsMachine adMachine = RetOps.of(machineResult)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
                //查询预发机
                KxsMachineAdvanceInfo kxsMachineAdvanceInfo = kxsMachineAdvanceInfoMapper.selectOne(Wrappers.<KxsMachineAdvanceInfo>lambdaQuery()
                        .eq(KxsMachineAdvanceInfo::getPosSn, advanceSn));

                if (adMachine == null){
                    throw new GlobalCustomerException(StoreErrorTypeEnum.MACHINE_IS_NULL.getDescription());
                }
                if (kxsMachineAdvanceInfo == null ) {
                    throw new GlobalCustomerException(StoreErrorTypeEnum.ADVANCE_MACHINE_NOT_FIND.getDescription());
                }
                if (kxsMachineAdvanceInfo.getIsConfirm() != 1) {
                    throw new GlobalCustomerException(StoreErrorTypeEnum.ADVANCE_MACHINE_NOT_CONFIRM.getDescription());
                }
                if (kxsMachineAdvanceInfo.getIsApply() != 0) {
                    throw new GlobalCustomerException(StoreErrorTypeEnum.ADVANCE_MACHINE_ERROR.getDescription());
                }
                if (kxsMachineAdvanceInfo.getIsReturn() != 0) {
                    throw new GlobalCustomerException(StoreErrorTypeEnum.ADVANCE_MACHINE_RETURN.getDescription());
                }
                //占用自己的预发额度
                if (kxsMachineAdvanceInfo.getIsUseAmount() == 1) {
                    //小分仓减少已用额度 刷新可用额度
                    Integer price = EnumUtil.getFieldBy(BrandTypeEnum::getType, BrandTypeEnum::getDescription, String.valueOf(brand.getBrandType()));
                    kxsWarehouseLimitService.refreshUserAmount(userId.intValue(), price, KindTypeEnum.SUB.getType());
                }
                //已经添加到预扣款
                if (kxsMachineAdvanceInfo.getAdvanceId() != null && kxsMachineAdvanceInfo.getAdvanceId() > 0) {
                    //查询当前的预扣款
                    R<KxsUserAdvance> advanceResult = remoteKxsUserService.loadByAdvanceId(kxsMachineAdvanceInfo.getAdvanceId(), SecurityConstants.FROM_IN);
                    KxsUserAdvance advance = RetOps.of(advanceResult)
                            .getData()
                            .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription()));
                    //预扣款未扣 删除该条预扣款
                    if (Objects.equals(advance.getStatus(), UserAdvanceStatusEnum.ADVANCE_NOT_CHARGED.getType())) {
                        R<Boolean> result = remoteKxsUserService.removeById(advance.getId(), SecurityConstants.FROM_IN);
                        if(!result.getData()){
                            throw new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription());
                        }
                    }
                    if(Objects.equals(advance.getStatus(), UserAdvanceStatusEnum.ADVANCE_CHARGED.getType())){
                        //预扣款已扣,返还给创客余额并修改预扣款为已返还
                        R<Boolean> result = remoteKxsUserService.returnAdvance(advance.getId(), SecurityConstants.FROM);
                        if(!result.getData()){
                            throw new GlobalCustomerException(StoreErrorTypeEnum.RETURN_ADVANCE_ERROR.getDescription());
                        }
                    }
                }
                //修改机具所属用户
                adMachine.setUserId(userId.intValue());
                //修改为申请的机具类型
                adMachine.setMachineType(param.getApplyType());
                //修改机具已出库
                adMachine.setStatus(MachineTypeEnum.STATUS_OUT.getType());
                adMachine.setDeliveryTime(LocalDateTime.now());
                //如果是兑换券申请则更新循环时间
                if(!param.getApplyType().equals(MachineOrderEnum.M_TYPE_RE.getType())){
                    recycleEndTime = LocalDateTime.now().plusDays(ParamResolver.getInteger("RECYC_POS_MAX_DAY", 365));
                }
                adMachine.setRecycleEndTime(recycleEndTime);
                adMachine.setRecycleStatus(MachineRecycleStatusEnum.UN_RECYCLE_STATUS.getType());
                R<Boolean> result = remoteKxsProductService.updateByMachine(adMachine, SecurityConstants.FROM_IN);
                if(!result.getData()){
                    throw new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription());
                }
                //机具已绑定 机具满足激活条件 && 绑定至申请时间 ≤ 30min
                if (Objects.equals(adMachine.getBindStatus(), CommonConstants.SUCCESS)) {
                    LocalDateTime bindTime = adMachine.getBindTime().plusMinutes(30);
                    if (bindTime.isAfter(LocalDateTime.now())) {
                        //TODO 走自动补录流程

                    }
                }
                //修改预发机状态
                kxsMachineAdvanceInfo.setIsApply(CommonConstants.SUCCESS);
                kxsMachineAdvanceInfoMapper.updateById(kxsMachineAdvanceInfo);

                //订单详情添加机具号
                orderDetail.setPosSn(adMachine.getPosSn());
                orderDetail.setMachineId(adMachine.getId());
            }
            kxsMachineApplyDetailMapper.insert(orderDetail);
        }


        return R.ok();
    }

    @Override
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public R applyVhostGdSn(ApplyMachineDTO param) {
        Long userId = SecurityUtils.getUser().getId();
        //虚拟仓库ID
        Integer whsId = ParamResolver.getInteger("GD_VHOST_STORE_ID", 8664);
        //订单号
        Snowflake snowflake = IdUtil.getSnowflake(1, userId);
        long orderSn = snowflake.nextId();

        KxsMachineApply order = new KxsMachineApply();
        BeanUtils.copyProperties(param, order);
        order.setOrderSn("VH" + orderSn);
        //查询申请用户
        R<KxsUser> userResult = remoteKxsUserService.loadUserById(userId.intValue(), SecurityConstants.FROM_IN);
        KxsUser user = RetOps.of(userResult)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
        order.setUserId(userId.intValue());
        order.setUsername(user.getUsername());
        order.setUserCode(user.getUserCode());
        order.setStatus(MachineOrderStatusEnum.APPLY_SUCCESSFUL.getType());
        order.setWarehouseId(whsId);
        //查询品牌
        R<KxsBrand> kxsBrandR = remoteKxsProductService.loadByBrand(param.getBrandId(), SecurityConstants.FROM_IN);
        KxsBrand brand = RetOps.of(kxsBrandR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription()));
        order.setBrandName(brand.getName());
        //添加订单
        baseMapper.insert(order);
        for (int i = 0; i < param.getSnList().size(); i++) {

            String sn = param.getSnList().get(i);

            //查询广电的虚拟SN在库
            R<KxsMachine> machineResult =  remoteKxsProductService.loadByWhsGdSn(whsId, SecurityConstants.FROM_IN);
            KxsMachine machine = RetOps.of(machineResult)
                    .getData()
                    .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.MACHINE_IS_NULL.getDescription()));
            //新增订单详情
            KxsMachineApplyDetail orderDetail = new KxsMachineApplyDetail();
            orderDetail.setOrderId(order.getId());
            orderDetail.setApplyType(param.getApplyType());
            //兑换券申请
            R<KxsTicket> ticketResult = remoteKxsProductService.loadTicketBySn(sn, SecurityConstants.FROM_IN);
            KxsTicket ticket = RetOps.of(ticketResult)
                    .getData()
                    .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.TICKET_NOT_FIND.getDescription()));
            //券码被使用返回错误
            if (!ticket.getStatus().equals(TicketStatusEnum.TICKET_UNUSED.getType())) {
                throw new GlobalCustomerException(StoreErrorTypeEnum.TICKET_CODE_UN.getDescription());
            }
            //冻结券码,发货后 驳回改回未使用 通过修改为已使用
            ticket.setStatus(TicketStatusEnum.TICKET_FREEZE.getType());
            R<Boolean> result = remoteKxsProductService.updateByTicket(ticket, SecurityConstants.FROM_IN);
            if (!result.getData()) {
                throw new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription());
            }
            orderDetail.setTicketId(ticket.getId());
            orderDetail.setTicketCode(sn);
            orderDetail.setMachineId(machine.getId());
            orderDetail.setPosSn(machine.getPosSn());
            kxsMachineApplyDetailMapper.insert(orderDetail);

            machine.setUserId(userId.intValue());
            //盟主标识
            machine.setLeaderId(ticket.getLeaderId());
            machine.setPartnerId(ticket.getPartnerId());
            //修改为申请的机具类型
            machine.setMachineType(param.getApplyType());
            //修改机具已出库
            machine.setStatus(MachineTypeEnum.STATUS_OUT.getType());
            machine.setRecycleEndTime(LocalDateTime.now().plusDays(ParamResolver.getInteger("RECYC_POS_MAX_DAY", 365)));
            R<Boolean> booleanR = remoteKxsProductService.updateByMachine(machine, SecurityConstants.FROM_IN);
            if(!booleanR.getData()){
                throw new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription());
            }
        }
//        发货统计
        kxsSendTotalService.shipmentStatistics(param.getSnList().size(), whsId, order.getBrandId());

        return R.ok();
    }

    @Override
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public R storeOrderTransferUser(StoreOrderTransferUserDTO param) {

        Long userId = SecurityUtils.getUser().getId();

        KxsMachineApply order = baseMapper.selectOne(Wrappers.<KxsMachineApply>lambdaQuery().eq(KxsMachineApply::getOrderSn, param.getOrderSn()));
        if(order == null){
            return R.failed(StoreErrorTypeEnum.ORDER_NULL.getDescription());
        }
        if(!Objects.equals(order.getStatus(), MachineOrderStatusEnum.UNDER_REVIEW.getType())){
            return R.failed(StoreErrorTypeEnum.ORDER_REPETITION_SUBMIT.getDescription());
        }
        //查询仓库
        KxsWarehouse warehouse = kxsWarehouseMapper.selectById(order.getWarehouseId());
        if(warehouse == null || warehouse.getUserId() != userId.intValue()){
            return R.failed(StoreErrorTypeEnum.WAREHOUSE_NOT_FIND.getDescription());
        }
        List<KxsMachineApplyDetail> orderDetails = kxsMachineApplyDetailMapper.selectList(Wrappers.<KxsMachineApplyDetail>lambdaQuery().eq(KxsMachineApplyDetail::getOrderId, order.getId()));
        List<String> snList = param.getSnList();
        //申请数量对应不上
        if(orderDetails.size() != snList.size()){
            return R.failed(StoreErrorTypeEnum.SN_SIZE_ERROR.getDescription());
        }

        //出库机具--修改为所属创客
        for (int i = 0; i < snList.size(); i++) {
            String sn = snList.get(i);
            KxsMachineApplyDetail orderDetail = orderDetails.get(i);
            //查询申请的机具
            R<KxsMachine> machineResult = remoteKxsProductService.loadMachineBySn(sn, SecurityConstants.FROM_IN);
            KxsMachine machine = RetOps.of(machineResult)
                    .getData()
                    .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
            if(machine.getStatus() != 0){
                throw new GlobalCustomerException(machine.getPosSn() + "机具状态不是在库!");
            }

            //划拨给订单用户
            machine.setUserId(order.getUserId());
            //修改状态为出库
            machine.setStatus(MachineTypeEnum.STATUS_OUT.getType());
            //如果为兑换机设置循环时间并设置为可循环申请
            if (order.getApplyType().equals(MachineOrderEnum.M_TYPE_SN.getType())) {
                machine.setRecycleEndTime(LocalDateTime.now().plusDays(ParamResolver.getInteger("RECYC_POS_MAX_DAY", 365)));
                //查询券
                R<KxsTicket> kxsTicketR = remoteKxsProductService.loadTicketBySn(orderDetail.getTicketCode(), SecurityConstants.FROM_IN);

                KxsTicket ticket = RetOps.of(kxsTicketR)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.TICKET_NOT_FIND.getDescription()));
                //盟主标识
                machine.setLeaderId(ticket.getLeaderId());
                machine.setPartnerId(ticket.getPartnerId());
            }else{
                //如果循环机则继承上级的循环时间
                R<KxsMachine> recycleMachineResult = remoteKxsProductService.loadMachineById(orderDetail.getRecycleMachineId(), SecurityConstants.FROM_IN);
                KxsMachine recycleMachine = RetOps.of(recycleMachineResult)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
                machine.setRecycleEndTime(recycleMachine.getRecycleEndTime());
                //盟主标识
                machine.setLeaderId(recycleMachine.getLeaderId());
                machine.setPartnerId(recycleMachine.getPartnerId());
                //增加循环记录表
                KxsMachineCirculationLog machineCirculationLog = new KxsMachineCirculationLog();
                R<KxsMachineCirculationLog> result = remoteKxsProductService.loadCirculationLogByMachineId(recycleMachine.getId(), SecurityConstants.FROM_IN);
                KxsMachineCirculationLog machineCirculationLogSuper = RetOps.of(result)
                        .getData()
                        .orElse(null);
                //有循环记录继承上级的
                if(machineCirculationLogSuper != null){
                    machineCirculationLog.setSourceSn(machineCirculationLogSuper.getSourceSn());
                    machineCirculationLog.setPidPath(machineCirculationLogSuper.getPidPath() + "," + recycleMachine.getId());
                }else{
                    machineCirculationLog.setSourceSn(recycleMachine.getPosSn());
                    machineCirculationLog.setPidPath("0," + recycleMachine.getId());
                }
                machineCirculationLog.setUserId(order.getUserId());
                machineCirculationLog.setMachineId(machine.getId());
                machineCirculationLog.setPid(recycleMachine.getId());
                machineCirculationLog.setOrderId(order.getId());

            }
            machine.setDeliveryTime(LocalDateTime.now());

            remoteKxsProductService.updateByMachine(machine, SecurityConstants.FROM_IN);

            //订单详情绑定机具
            orderDetail.setMachineId(machine.getId());
            orderDetail.setPosSn(machine.getPosSn());
            kxsMachineApplyDetailMapper.updateById(orderDetail);

            if (machine.getBindStatus() == 1 ) {
                LocalDateTime bindTime = machine.getBindTime().plusMinutes(30);
                if (bindTime.isAfter(LocalDateTime.now())) {
                    //TODO 走自动补录流程

                }
            }

        }
        //修改仓库库存
        KxsWarehouseStock warehouseStock = kxsWarehouseStockService.updateDeliveryStock(order.getWarehouseId(), snList.size());
        //新增仓库日志记录
        kxsWarehouseStockLogService.addKxsWarehouseStockLog(order.getWarehouseId(), order.getBrandId(), warehouseStock, KindTypeEnum.SUB.getType(), 1, snList.size());
        //修改订单状态
        order.setStatus(MachineOrderStatusEnum.APPLY_SUCCESSFUL.getType());
        baseMapper.updateById(order);
        //刷新仓库额度
        R<KxsBrand> kxsBrandR = remoteKxsProductService.loadByBrand(order.getBrandId(), SecurityConstants.FROM_IN);
        KxsBrand kxsBrand = RetOps.of(kxsBrandR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription()));
        Integer price = EnumUtil.getFieldBy(BrandTypeEnum::getType, BrandTypeEnum::getDescription, String.valueOf(kxsBrand.getBrandType()));
        int amount = snList.size() * price;
        //减少仓库已用额度增加仓库可用额度
        kxsWarehouseLimitService.refreshWarehouseAmount(userId.intValue(), amount, KindTypeEnum.SUB.getType());

        //发货统计
        kxsSendTotalService.shipmentStatistics(param.getSnList().size(), order.getWarehouseId(), order.getBrandId());

        return R.ok();
    }

    @Override
    public IPage<StoreOrderListVO> getByPage(Page<StoreOrderListVO> page, StoreOrderListDTO param) {
        //查询用户下的所有仓库
        if(param.getWarehouseId() == null || param.getWarehouseId() == 0){
            Long userId = SecurityUtils.getUser().getId();
            List<KxsWarehouse> kxsWarehouses = kxsWarehouseMapper.selectList(Wrappers.<KxsWarehouse>lambdaQuery().eq(KxsWarehouse::getUserId, userId));
            param.setWhsIds(kxsWarehouses.stream().map(KxsWarehouse::getId).collect(Collectors.toList()));
        }

        IPage<StoreOrderListVO> byPage = baseMapper.getByPage(page, param);
        //如果已完成的订单才去查询机具号
        for (StoreOrderListVO orderListVo : byPage.getRecords()) {
            if (Objects.equals(orderListVo.getStatus(), MachineOrderStatusEnum.APPLY_SUCCESSFUL.getType())) {
                List<KxsMachineApplyDetail> orderDetails = kxsMachineApplyDetailMapper.selectList(Wrappers.<KxsMachineApplyDetail>lambdaQuery().eq(KxsMachineApplyDetail::getOrderId, orderListVo.getId()));
                orderListVo.setSnList(orderDetails.stream().map(KxsMachineApplyDetail::getPosSn).collect(Collectors.toList()));
            }
        }
        return byPage;
    }

    @Override
    public StoreOrderDetailVO storeOrderDetail(Integer id) {

        KxsMachineApply order = baseMapper.selectById(id);
        Optional.ofNullable(order).orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.ORDER_NULL.getDescription()));
        List<KxsMachineApplyDetail> orderDetail = kxsMachineApplyDetailMapper.selectList(Wrappers.<KxsMachineApplyDetail>lambdaQuery().eq(KxsMachineApplyDetail::getOrderId, id));
        StoreOrderDetailVO orderDetailVO = new StoreOrderDetailVO();
        BeanUtils.copyProperties(order, orderDetailVO);
        orderDetailVO.setSnList(orderDetail.stream().map(KxsMachineApplyDetail::getPosSn).collect(Collectors.toList()));

        return orderDetailVO;
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public R orderCancel(KxsMachineApply param) {
        KxsMachineApply order = baseMapper.selectById(param.getId());

        if(Objects.equals(order.getStatus(), MachineOrderStatusEnum.APPLY_SUCCESSFUL.getType())){
            return R.failed(StoreErrorTypeEnum.ORDER_REPETITION_TRANSFER.getDescription());
        }
        if(Objects.equals(order.getStatus(), MachineOrderStatusEnum.REJECTED.getType())){
            return R.failed(StoreErrorTypeEnum.ORDER_REPETITION_CANCEL.getDescription());
        }
        order.setStatus(MachineOrderStatusEnum.REJECTED.getType());
        baseMapper.updateById(order);
        //查询订单详情回退券码状态
        List<KxsMachineApplyDetail> orderDetail = kxsMachineApplyDetailMapper.selectList(Wrappers.<KxsMachineApplyDetail>lambdaQuery().eq(KxsMachineApplyDetail::getOrderId, param.getId()));
        List<String> snList = new ArrayList<>();
        for (KxsMachineApplyDetail detail : orderDetail) {
            //兑换券申请 修改兑换券可使用
            if (detail.getApplyType().equals(MachineOrderEnum.M_TYPE_SN.getType())) {
                R<KxsTicket> kxsTicketR = remoteKxsProductService.loadTicketBySn(detail.getTicketCode(), SecurityConstants.FROM_IN);
                KxsTicket ticket = RetOps.of(kxsTicketR)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
                ticket.setStatus(TicketStatusEnum.TICKET_UNUSED.getType());
                R<Boolean> booleanR = remoteKxsProductService.updateByTicket(ticket, SecurityConstants.FROM_IN);
                if(!booleanR.getData()){
                    throw new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription());
                }
                snList.add(ticket.getTicketCode());
            }else{
                //循环机申请
                R<KxsMachine> kxsMachineR = remoteKxsProductService.loadMachineById(detail.getRecycleMachineId(), SecurityConstants.FROM_IN);
                KxsMachine machine = RetOps.of(kxsMachineR)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
                //驳回订单设置为可循环
                machine.setRecycleStatus(MachineRecycleStatusEnum.CAN_RECYCLE_STATUS.getType());
                R<Boolean> booleanR = remoteKxsProductService.updateByMachine(machine, SecurityConstants.FROM_IN);
                if(!booleanR.getData()){
                    throw new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription());
                }
                snList.add(machine.getPosSn());
            }

        }
        //查询品牌
        R<KxsBrand> kxsBrandR = remoteKxsProductService.loadByBrand(order.getBrandId(), SecurityConstants.FROM_IN);
        KxsBrand brand = RetOps.of(kxsBrandR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription()));

        //查询仓库
        KxsWarehouse warehouse = kxsWarehouseMapper.selectById(order.getWarehouseId());
        //发送消息
        KxsUserMsg userMsg = MsgTemplateUtil.orderCancel(order.getUserId(), snList, brand.getName(), warehouse.getWarehouseName(), warehouse.getWarehousePhone(), order.getOrderSn());
        R<Boolean> booleanR = remoteUserMsgService.pushUserMsg(userMsg, SecurityConstants.FROM_IN);
        if(!booleanR.getData()){
            throw new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription());
        }

        return R.ok();
    }

    @Override
    public IPage<UserApplyMahineListVO> userApplyMachineList(Page<UserApplyMahineListVO> page) {

        IPage<UserApplyMahineListVO> pageList = baseMapper.userApplyMachineList(page, SecurityUtils.getUser().getId());
        for (UserApplyMahineListVO record : pageList.getRecords()) {
            String statusNo = EnumUtil.getFieldBy(MachineOrderStatusEnum::getDescription, MachineOrderStatusEnum::getType, record.getStatus());
            record.setStatusNo(statusNo);
        }
        return pageList;
    }

    @Override
    public UserApplyMachineDetailVO userApplyMachineDetail(Long id) {

        UserApplyMachineDetailVO userApplyMachineDetailVO = new UserApplyMachineDetailVO();
        KxsMachineApply order = baseMapper.selectById(id);
        Optional.ofNullable(order).orElseThrow(() -> new GlobalCustomerException(ErrorTypeEnum.PARAM_ERROR.getDescription()));
        BeanUtil.copyProperties(order, userApplyMachineDetailVO);
        //查询仓库
        KxsWarehouse warehouse = kxsWarehouseMapper.selectById(order.getWarehouseId());
        if(warehouse != null){
            userApplyMachineDetailVO.setWarehouseName(warehouse.getWarehouseName() + "--" + warehouse.getBrandName());
            userApplyMachineDetailVO.setWarehousePhone(warehouse.getWarehousePhone());
        }

        //订单状态
        String statusNo = EnumUtil.getFieldBy(MachineOrderStatusEnum::getDescription, MachineOrderStatusEnum::getType, order.getStatus());
        userApplyMachineDetailVO.setStatusNo(statusNo);
        //查询订单详情
        List<KxsMachineApplyDetail> orderInfos = kxsMachineApplyDetailMapper.selectList(Wrappers.lambdaQuery(KxsMachineApplyDetail.class).eq(KxsMachineApplyDetail::getOrderId, order.getId()));
        //兑换机申请
        if(Objects.equals(order.getApplyType(), MachineOrderEnum.M_TYPE_SN.getType())){
            List<String> snList = orderInfos.stream().map(KxsMachineApplyDetail::getTicketCode).toList();
            userApplyMachineDetailVO.setSnList(snList);
        }else{
            //循环机申请
            for (KxsMachineApplyDetail orderInfo : orderInfos) {
                R<KxsMachine> kxsMachineR = remoteKxsProductService.loadMachineById(orderInfo.getRecycleMachineId(), SecurityConstants.FROM_IN);
                KxsMachine machine = RetOps.of(kxsMachineR)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
                //兑换机
                if(Objects.equals(machine.getMachineType(), MachineTypeEnum.M_TYPE_SN.getType())){
                    userApplyMachineDetailVO.getSnList().add(machine.getPosSn() + ":" + MachineTypeEnum.M_TYPE_SN.getDescription());
                }else{
                    userApplyMachineDetailVO.getSnList().add(machine.getPosSn() + ":" + MachineTypeEnum.M_TYPE_RE.getDescription());
                }
            }
        }
        return userApplyMachineDetailVO;
    }

}

