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

import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
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.BrandTypeEnum;
import com.kxs.common.core.constant.enums.ErrorTypeEnum;
import com.kxs.common.core.constant.enums.KindTypeEnum;
import com.kxs.common.core.constant.enums.MachineTypeEnum;
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.store.api.dto.kxsapp.storeAdvance.StoreAdvanceAddAdvanceDTO;
import com.kxs.store.api.dto.kxsapp.userAdvance.ConfirmAdvanceMachineDTO;
import com.kxs.store.api.model.*;
import com.kxs.store.api.vo.kxsapp.store.StoreAdvanceMachineVO;
import com.kxs.store.api.vo.kxsapp.storeAdvance.UserWarehouseListVO;
import com.kxs.store.api.vo.kxsapp.userAdvance.AdvanceDevModalVO;
import com.kxs.store.api.vo.kxsapp.userAdvance.UserAdvanceListVO;
import com.kxs.store.biz.constant.enums.StoreErrorTypeEnum;
import com.kxs.store.biz.constant.enums.StoreStatusEnum;
import com.kxs.store.biz.constant.enums.WarehouseLimitTypeEnum;
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 io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static org.bouncycastle.asn1.x500.style.RFC4519Style.sn;

/**
 * 客小爽预发机表(KxsMachineAdvance)表服务实现类
 *
 * @author 系统
 * @since 2024-01-08 09:46:02
 */
@Service("kxsMachineAdvanceService")
@RequiredArgsConstructor
public class KxsMachineAdvanceServiceImpl extends ServiceImpl<KxsMachineAdvanceMapper, KxsMachineAdvance> implements KxsMachineAdvanceService {

    private final KxsWarehouseMapper kxsWarehouseMapper;

    private final KxsWarehouseLimitMapper kxsWarehouseLimitMapper;

    private final KxsWarehouseLimitService kxsWarehouseLimitService;

    private final RemoteKxsUserService remoteKxsUserService;

    private final RemoteKxsProductService remoteKxsProductService;

    private final RemoteUserMsgService remoteUserMsgService;

    private final KxsMachineAdvanceInfoMapper kxsMachineAdvanceInfoMapper;

    private final KxsWarehouseStockService kxsWarehouseStockService;

    private final KxsSendTotalService kxsSendTotalService;

    private final KxsWarehouseStockLogService kxsWarehouseStockLogService;


    @Override
    public IPage<StoreAdvanceMachineVO> getByPage(Page<StoreAdvanceMachineVO> page, Integer warehouseId, Integer brandId) {

        return baseMapper.getByPage(page, warehouseId, brandId);
    }

    @Override
    public IPage<UserWarehouseListVO> getUserWareHouseList(Page<UserWarehouseListVO> page, String keyword) {

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

        /*
          查询思路
          <p>
              先查询仓库用户下所有的小分仓用户分页
              通过仓库用户和小分仓用户查询预发机订单的品牌信息
          </p>
         */
        IPage<UserWarehouseListVO> userWareHouseList = baseMapper.getUserWareHouseList(page, userId, keyword);
        for (UserWarehouseListVO record : userWareHouseList.getRecords()) {

            //查询仓库用户下所有用户的预发机
            List<Map<String, Object>> kxsMachineAdvances = baseMapper.selectToUserList(userId, record.getUserId(), keyword == null || keyword.startsWith(CommonConstants.KXS_USER_NUMBER_PREFIX) ? null : keyword);

            //按照品牌ID分组
            Map<String, List<Map<String, Object>>> advanceDevMap = kxsMachineAdvances.stream().collect(Collectors.groupingBy((item -> item.get("brandName").toString())));
            ArrayList<Object> brandList = new ArrayList<>();
            advanceDevMap.forEach((brandName, item) -> {
                HashMap<String, Object> map = new HashMap<>();
                map.put("brandName", brandName);//品牌名
                ArrayList<Object> snList = new ArrayList<>();
                if (item instanceof ArrayList<Map<String, Object>> list) {
                    for (Map<String, Object> info : list) {
                        HashMap<String, Object> sn = new HashMap<>();
                        sn.put("id", info.get("infoId"));//预发机id
                        sn.put("posSn", info.get("posSn"));//机具sn
                        sn.put("isUseAmount", info.get("isUseAmount"));//是否占用语法额度  0否  1是
                        sn.put("isAdvance", info.get("isAdvance"));//是否预扣款 0否 1是
                        sn.put("isConfirm", info.get("isConfirm"));//是否确认收货  0未确认 1已确认  2已拒绝
                        sn.put("createTime", info.get("createTime"));//创建时间
                        sn.put("brandId", info.get("brandId"));//品牌id
                        snList.add(sn);
                    }
                }
                map.put("snList", snList);
                brandList.add(map);
            });
            record.setBrandList(brandList);
        }
        return userWareHouseList;
    }

    @Override
    @GlobalTransactional
    @Transactional(rollbackFor = Exception.class)
    public R cancelAdvance(KxsMachineAdvanceInfo advance) {

        if (StrUtil.isBlank(advance.getPosSn())) {
            return R.failed("机具号不能为空");
        }
        KxsMachineAdvanceInfo machineAdvanceInfo = kxsMachineAdvanceInfoMapper
                .selectOne(Wrappers.<KxsMachineAdvanceInfo>lambdaQuery()
                        .eq(KxsMachineAdvanceInfo::getIsReturn, CommonConstants.FAIL)
                        .eq(KxsMachineAdvanceInfo::getIsApply, CommonConstants.FAIL)
                        .eq(KxsMachineAdvanceInfo::getPosSn, advance.getPosSn()));
        Optional.ofNullable(machineAdvanceInfo).orElseThrow(() -> new GlobalCustomerException("该机具已被接收/已撤回"));

        machineAdvanceInfo.setIsReturn(CommonConstants.SUCCESS);
        machineAdvanceInfo.setReturnTime(LocalDateTime.now());


        //修改状态为在库
        KxsMachine machine = new KxsMachine();
        machine.setId(machineAdvanceInfo.getMachineId());
        machine.setStatus(MachineTypeEnum.STATUS_IS.getType());
        machine.setPreUserId(0);
        R<Boolean> result = remoteKxsProductService.updateByMachine(machine, SecurityConstants.FROM_IN);
        if(!result.getData()){
            throw new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription());
        }

        //查询主订单预发机
        KxsMachineAdvance kxsMachineAdvance = baseMapper.selectById(machineAdvanceInfo.getOrderId());

        if(Objects.equals(machineAdvanceInfo.getIsUseAmount(), CommonConstants.SUCCESS)){

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

            //小分仓减少已用额度 刷新可用额度
            Integer price = EnumUtil.getFieldBy(BrandTypeEnum::getType, BrandTypeEnum::getDescription, String.valueOf(brand.getBrandType()));
            kxsWarehouseLimitService.refreshUserAmount(kxsMachineAdvance.getToUserId(), price, KindTypeEnum.SUB.getType());
            //增加仓库已用额度减少仓库可用额度
            kxsWarehouseLimitService.refreshWarehouseAmount(kxsMachineAdvance.getSendUserId(), price, KindTypeEnum.ADD.getType());
        }
        //直接删除记录
        kxsMachineAdvanceInfoMapper.deleteById(machineAdvanceInfo.getId());
        baseMapper.deleteById(machineAdvanceInfo.getOrderId());
        //查询用户
        R<KxsUser> kxsUserR = remoteKxsUserService.loadUserById(kxsMachineAdvance.getToUserId(), SecurityConstants.FROM_IN);
        KxsUser toUser = RetOps.of(kxsUserR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(ErrorTypeEnum.USER_NOT_FOUND.getDescription()));

        //给仓库所属人发送消息
        KxsUserMsg sendUserMsg = MsgTemplateUtil.cancelAdvanceNote(machineAdvanceInfo.getPosSn(), kxsMachineAdvance.getSendUserId(), toUser.getUserCode(), toUser.getUsername());
        remoteUserMsgService.pushUserMsg(sendUserMsg, SecurityConstants.FROM_IN);
        //给用户发送消息
        KxsUserMsg toUserMsg = MsgTemplateUtil.cancelAdvanceNote(machineAdvanceInfo.getPosSn(), kxsMachineAdvance.getToUserId(), kxsMachineAdvance.getWarehouseName());
        remoteUserMsgService.pushUserMsg(toUserMsg, SecurityConstants.FROM_IN);

        return R.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addAdvanceMachine(StoreAdvanceAddAdvanceDTO param) {

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

        //查询预发用户
        R<KxsUser> kxsUserR = remoteKxsUserService.loadUserByCode(param.getUserCode(), SecurityConstants.FROM_IN);
        KxsUser toUser = RetOps.of(kxsUserR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(ErrorTypeEnum.USER_NOT_FOUND.getDescription()));

        String pidPath = toUser.getPidPath();

        //判断是否是下级
        boolean contains = pidPath.contains(StrUtil.COMMA + userId + StrUtil.COMMA);
        if (!contains) {
            return R.failed(StoreErrorTypeEnum.USER_IS_NOT_FIND.getDescription());
        }
        //判断用户是否具备小分仓
        KxsWarehouseLimit kxsWarehouseLimit = kxsWarehouseLimitMapper.selectOne(Wrappers.<KxsWarehouseLimit>query().lambda().eq(KxsWarehouseLimit::getUserId, toUser.getId()));
        //当用户不存在小分仓时为用户构建小分仓
        if (kxsWarehouseLimit == null){
            //构建用户小分仓
            //todo 此时需同步用户上月分润金额作为小分仓额度,暂时无法实现 初始化为0
            kxsWarehouseLimit = new KxsWarehouseLimit();
            kxsWarehouseLimit.setUserId(toUser.getId());
            kxsWarehouseLimit.setValidAmount(BigDecimal.ZERO);
            kxsWarehouseLimit.setFixedAmount(BigDecimal.ZERO);
            kxsWarehouseLimit.setForAmount(BigDecimal.ZERO);
            kxsWarehouseLimit.setCreditAmount(BigDecimal.ZERO);
            kxsWarehouseLimit.setYueForAmount(BigDecimal.ZERO);
            kxsWarehouseLimit.setUsedAmount(BigDecimal.ZERO);
            kxsWarehouseLimit.setWarehouseType(WarehouseLimitTypeEnum.XFC.getType());
            kxsWarehouseLimitMapper.insert(kxsWarehouseLimit);
        }
        //预发数量
        Long advanceCount = baseMapper.selectUserByCount(toUser.getId());
        //预发数量+本次申请数量不能超过10
        Integer preMaxNum = ParamResolver.getInteger("PRE_POS_MAX_NUM", 10);
        if (advanceCount + param.getSnList().size() > preMaxNum) {
            return R.failed(StoreErrorTypeEnum.ADVANCE_MACHINE_NUMBER_ERROR.getDescription());
        }
        //查询仓库
        KxsWarehouse warehouse = kxsWarehouseMapper.selectById(param.getWarehouseId());

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

        //新增预发机订单表
        KxsMachineAdvance kxsMachineAdvance = new KxsMachineAdvance();
        kxsMachineAdvance.setSendUserId(userId.intValue());
        kxsMachineAdvance.setBrandId(brand.getId());
        kxsMachineAdvance.setBrandName(brand.getName());
        kxsMachineAdvance.setToUserId(toUser.getId());
        kxsMachineAdvance.setWarehouseId(param.getWarehouseId());
        kxsMachineAdvance.setWarehouseName(warehouse.getWarehouseName());
        baseMapper.insert(kxsMachineAdvance);

        for (String sn : param.getSnList()) {
            R<KxsMachine> kxsMachineR = remoteKxsProductService.loadMachineBySn(sn, SecurityConstants.FROM_IN);
            KxsMachine machine = RetOps.of(kxsMachineR)
                    .getData()
                    .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
            if(machine.getPreUserId() > 0){
                throw new GlobalCustomerException("机具已"+machine.getPosSn()+"预发，不能重复预发");
            }
            //新增预发机明细
            KxsMachineAdvanceInfo kxsMachineAdvanceInfo = new KxsMachineAdvanceInfo();
            kxsMachineAdvanceInfo.setOrderId(kxsMachineAdvance.getId());
            kxsMachineAdvanceInfo.setPosSn(machine.getPosSn());
            kxsMachineAdvanceInfo.setMachineId(machine.getId());
            kxsMachineAdvanceInfoMapper.insert(kxsMachineAdvanceInfo);

            //修改状态为预发机
            machine.setPreUserId(toUser.getId());
            R<Boolean> result = remoteKxsProductService.updateByMachine(machine, SecurityConstants.FROM_IN);
            if(!result.getData()){
                throw new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription());
            }
        }

        //申请的预发机 修改仓库库存
        KxsWarehouseStock warehouseStock = kxsWarehouseStockService.updateDeliveryStock(param.getWarehouseId(), param.getSnList().size());
        //新增仓库日志记录
        kxsWarehouseStockLogService.addKxsWarehouseStockLog(param.getWarehouseId(),
                param.getBrandId(), warehouseStock, KindTypeEnum.SUB.getType(),
                StoreStatusEnum.STOCK_PUSH.getType(), param.getSnList().size());
        //发货统计
        kxsSendTotalService.shipmentStatistics(param.getSnList().size(), param.getWarehouseId(), param.getBrandId());


        return R.ok();
    }

    @Override
    public List<AdvanceDevModalVO> advanceDevModal() {

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

        return baseMapper.selectToUserNeedConfirmList(userId);
    }

    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public R confirmAdvanceMachine(ConfirmAdvanceMachineDTO param) {

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

        R<KxsUser> kxsUserR = remoteKxsUserService.loadUserById(userId.intValue(), SecurityConstants.FROM_IN);
        KxsUser toUser = RetOps.of(kxsUserR)
                .getData()
                .orElseThrow(() -> new GlobalCustomerException(ErrorTypeEnum.USER_NOT_FOUND.getDescription()));

        for (String sn : param.getSnList()) {
            KxsMachineAdvanceInfo machineAdvanceInfo = kxsMachineAdvanceInfoMapper.selectOne(Wrappers.<KxsMachineAdvanceInfo>lambdaQuery()
                            .eq(KxsMachineAdvanceInfo::getIsConfirm, CommonConstants.FAIL)
                            .eq(KxsMachineAdvanceInfo::getIsReturn, CommonConstants.FAIL)
                    .eq(KxsMachineAdvanceInfo::getPosSn, sn));
            if(machineAdvanceInfo == null){
                throw new GlobalCustomerException(sn + "已确认/已撤回");
            }
            KxsMachineAdvance machineAdvance = baseMapper.selectById(machineAdvanceInfo.getOrderId());

            //查询仓库
            KxsWarehouse warehouse = kxsWarehouseMapper.selectById(machineAdvance.getWarehouseId());
            //查询品牌
            R<KxsBrand> kxsBrandR = remoteKxsProductService.loadByBrand(machineAdvance.getBrandId(), SecurityConstants.FROM_IN);
            KxsBrand brand = RetOps.of(kxsBrandR)
                    .getData()
                    .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.DATA_ERROR.getDescription()));

            //查询用户预发额度
            KxsWarehouseLimit userLimit = kxsWarehouseLimitMapper.selectOne(Wrappers.<KxsWarehouseLimit>lambdaQuery()
                    .eq(KxsWarehouseLimit::getWarehouseType, WarehouseLimitTypeEnum.XFC.getType())
                    .eq(KxsWarehouseLimit::getUserId, userId));

            //同意
            if (Objects.equals(param.getConfirmType(), CommonConstants.SUCCESS)) {
                //扣减用户预发额度
                int amount;
                if (Objects.equals(brand.getBrandType(), BrandTypeEnum.DIANQIAN.getType())) {
                    //电签
                    amount = BrandTypeEnum.DQ_PRICE.getType();
                } else {
                    amount = BrandTypeEnum.DJ_PRICE.getType();
                }
                //额度充足
                if (userLimit.getValidAmount().compareTo(BigDecimal.valueOf(amount)) >= 0) {

                    //小分仓增加已用额度 刷新可用额度
                    userLimit.setUsedAmount(NumberUtil.add(userLimit.getUsedAmount(), amount));
                    userLimit.setValidAmount(NumberUtil.sub(userLimit.getValidAmount(), amount));
                    kxsWarehouseLimitMapper.updateById(userLimit);

                    //减少仓库已用额度增加仓库可用额度
                    kxsWarehouseLimitService.refreshWarehouseAmount(warehouse.getUserId(), amount, KindTypeEnum.SUB.getType());
                }
                //修改为占用预发额度标签
                if (userLimit.getValidAmount().compareTo(BigDecimal.valueOf(amount)) >= 0) {
                    machineAdvanceInfo.setIsUseAmount(CommonConstants.SUCCESS);
                }
                machineAdvanceInfo.setIsConfirm(CommonConstants.SUCCESS);
                kxsMachineAdvanceInfoMapper.updateById(machineAdvanceInfo);
                //给预发对象发送通知
                KxsUserMsg toUserMsg = MsgTemplateUtil.confirmAdvanceMachineUserNote(userId.intValue(), warehouse.getWarehouseName(), machineAdvance.getBrandName(), param.getSnList());
                //给仓库发送通知
                KxsUserMsg toWarehouseMsg = MsgTemplateUtil.confirmAdvanceMachineWarehoiuseNote(warehouse.getUserId(), toUser.getUserCode(), toUser.getUsername(), warehouse.getWarehouseName(), brand.getName(), param.getSnList());
                remoteUserMsgService.pushUserMsg(toUserMsg, SecurityConstants.FROM_IN);
                remoteUserMsgService.pushUserMsg(toWarehouseMsg, SecurityConstants.FROM_IN);

            } else {

                //拒绝,直接删除记录
//                machineAdvanceInfo.setIsConfirm(2);
                kxsMachineAdvanceInfoMapper.deleteById(machineAdvanceInfo.getId());
                baseMapper.deleteById(machineAdvanceInfo.getOrderId());

                //修改状态为在库
                KxsMachine machine = new KxsMachine();
                machine.setId(machineAdvanceInfo.getMachineId());
                machine.setStatus(MachineTypeEnum.STATUS_IS.getType());
                machine.setPreUserId(0);
                R<Boolean> result = remoteKxsProductService.updateByMachine(machine, SecurityConstants.FROM_IN);
                if(!result.getData()){
                    throw new GlobalCustomerException(ErrorTypeEnum.REMOTE_DATA_ERROR.getDescription());
                }

                //给仓库发送模版消息
                KxsUserMsg toWarehouseMsg = MsgTemplateUtil.advanceMachineCancelWarehouseNote(warehouse.getUserId(), toUser.getUserCode(), toUser.getUsername(), warehouse.getWarehouseName(), brand.getName(), param.getSnList());
                //给用户发送消息
                KxsUserMsg toUserMsg = MsgTemplateUtil.cancelAdvanceMachineUserNote(userId.intValue(), warehouse.getWarehouseName(), machineAdvance.getBrandName(), param.getSnList());

                remoteUserMsgService.pushUserMsg(toUserMsg, SecurityConstants.FROM_IN);
                remoteUserMsgService.pushUserMsg(toWarehouseMsg, SecurityConstants.FROM_IN);
            }
        }


        return R.ok();
    }

    @Override
    public List<UserAdvanceListVO> advanceUserList() {

        Long userId = SecurityUtils.getUser().getId();
        List<UserAdvanceListVO> userAdvanceList = baseMapper.advanceUserList(userId);
        for (UserAdvanceListVO advanceListVO : userAdvanceList) {

            //只有广电卡查询地址信息
            if(advanceListVO.getBrandId() == 14){
                R<KxsMachine> kxsMachineR = remoteKxsProductService.loadMachineBySn(advanceListVO.getPosSn(), SecurityConstants.FROM_IN);
                KxsMachine machine = RetOps.of(kxsMachineR)
                        .getData()
                        .orElseThrow(() -> new GlobalCustomerException(StoreErrorTypeEnum.SN_FIND_NULL.getDescription()));
                advanceListVO.setAreas(machine.getDevLocation());
            }
        }
        return userAdvanceList;
    }

    @Override
    public Integer userPrePosModal() {

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

        return baseMapper.selectMaxDayPreTimeout(userId);
    }

    @Override
    public List<String> userPrePosBindModal() {

        R<List<String>> listR = remoteKxsProductService.loadByPrePosBind30minute(SecurityConstants.FROM_IN);
        List<String> sns = listR.getData();
        if(!sns.isEmpty()){
            List<UserAdvanceListVO> advanceList = baseMapper.advanceUserList(SecurityUtils.getUser().getId());

            sns = advanceList.stream()
                    .map(UserAdvanceListVO::getPosSn)
                    .filter(sns::contains)
                    .toList();
        }
        return sns;
    }


}

