package com.junmp.jyzb.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.junmp.jyzb.api.bean.dto.CabinetBoxDto;
import com.junmp.jyzb.api.bean.dto.CabinetDto;
import com.junmp.jyzb.api.bean.query.CabinetBoxReq;
import com.junmp.jyzb.api.bean.req.UpdateCabinetBoxReq;
import com.junmp.jyzb.api.bean.req.UpdateCabinetReq;
import com.junmp.jyzb.entity.*;
import com.junmp.jyzb.api.exception.enums.CabinetBoxExceptionEnum;
import com.junmp.jyzb.api.exception.enums.CabinetExceptionEnum;
import com.junmp.jyzb.mapper.CabinetBoxMapper;
import com.junmp.jyzb.mapper.InventoryMapper;
import com.junmp.jyzb.mapper.InventorySummaryMapper;
import com.junmp.jyzb.mapper.WarehouseInventoryMapper;
import com.junmp.jyzb.service.*;
import com.junmp.jyzb.utils.RabbitMQSendMsg;
import com.junmp.v2.common.exception.base.ServiceException;
import com.junmp.v2.common.util.BeanPlusUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class CabinetBoxServiceImpl extends ServiceImpl<CabinetBoxMapper, CabinetBox> implements CabinetBoxService {


    @Resource
    private CabinetService cabinetService;
    @Autowired
    private RabbitMQSendMsg MQ;

    @Resource
    private CabinetBoxMapper cabinetBoxMapper;

    @Resource
    private CabinetBoxPoliceService cabinetBoxPoliceService;

    @Resource
    private InventoryService inventoryService;

    @Resource
    private WarehouseInventoryService warehouseInventoryService;

    @Resource
    private InventorySummaryMapper inventorySummaryMapper;

    @Resource
    private InventorySummaryService inventorySummaryService;


    /**
     * 添加箱门信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CabinetDto AddOrUpdateBoxInfo(UpdateCabinetReq req) {
        Cabinet cabinet = cabinetService.getOne(new LambdaQueryWrapper<Cabinet>()
                .eq(Cabinet::getDevSn, req.getDevSn()));
        if (ObjectUtil.isNull(cabinet)) {
            throw new ServiceException(CabinetExceptionEnum.CABINET_ISNOT_EXISTS);
        }
        List<UpdateCabinetBoxReq> addList = req.getCabinetBoxList();
        //查询箱门信息
        List<CabinetBox> existingBoxes = list(new LambdaQueryWrapper<CabinetBox>()
                .eq(CabinetBox::getCabinetId, cabinet.getId()));
        Map<String, CabinetBox> existingBoxMap = existingBoxes.stream()
                .collect(Collectors.toMap(CabinetBox::getBoxLocalId, Function.identity()));

        List<CabinetBox> boxListAdd = new ArrayList<>();
        int addNum = 0;
        for (UpdateCabinetBoxReq boxReq : addList) {
            CabinetBox box = BeanPlusUtil.toBean(boxReq, CabinetBox.class);
            box.setCabinetId(cabinet.getId());
            box.setState(ObjectUtil.isNotEmpty(boxReq.getState())?boxReq.getState():1);

            // 在内存中比较是否存在相同 SerialNum 和相同 num 的数据
            CabinetBox existingBox = existingBoxMap.get(boxReq.getBoxLocalId());
            if (existingBox != null) {
                // 如果存在，则更新数据
                box.setId(existingBox.getId());
                box.setUpdateTime(new Date());
                updateById(box);
            } else {
                // 如果不存在，则新增数据
                addNum += 1;
                box.setCreateTime(new Date());
                boxListAdd.add(box);
            }
        }
        //获取当前柜的总数量
        Integer num = cabinet.getNum();
        if (num == null) {
            num = 0;
        } else {
            num += addNum;
        }
        cabinet.setNum(num);
        cabinetService.updateById(cabinet);
        // 批量保存新增的数据
        saveBatch(boxListAdd);

        if (ObjectUtil.isNotEmpty(req.getActionFrom()) && req.getActionFrom().equals("platform")) {
            //请求来源于平台，则进行推送
            MQ.SendMsg("cabinetMsg", req.getDevSn(), "cabinetChange");
        }
        CabinetDto cabinetDto = new CabinetDto();
        List<CabinetBoxDto> collect;
        if (CollectionUtil.isNotEmpty(boxListAdd)){
            //根据查询的结果将id进行返回
//            List<String> localBoxIds = req.getCabinetBoxList().stream().map(UpdateCabinetBoxReq::getBoxLocalId).collect(Collectors.toList());
//            List<CabinetBox> list = list(new LambdaQueryWrapper<CabinetBox>().eq(CabinetBox::getCabinetId, cabinet.getId()).in(CabinetBox::getBoxLocalId,localBoxIds ));
            collect = boxListAdd.stream().map(cabinetBox -> {
                        CabinetBoxDto cabinetBoxDto = new CabinetBoxDto();
                        BeanPlusUtil.copyProperties(cabinetBox, cabinetBoxDto);
                        return cabinetBoxDto;
                    }
            ).collect(Collectors.toList());
        }else {
            collect = addList.stream().map(cabinetBox -> {
                        CabinetBoxDto cabinetBoxDto = new CabinetBoxDto();
                        BeanPlusUtil.copyProperties(cabinetBox, cabinetBoxDto);
                        return cabinetBoxDto;
                    }
            ).collect(Collectors.toList());
        }

        BeanPlusUtil.copyProperties(req,cabinetDto);
        cabinetDto.setCabinetBoxList(collect);
        return cabinetDto;
    }

    //删除箱门
    @Override
    @Transactional(rollbackFor = Exception.class)
    public CabinetDto DeleteBox(UpdateCabinetReq req) {
        Cabinet cabinet = cabinetService.getOne(new LambdaQueryWrapper<Cabinet>()
                .eq(Cabinet::getDevSn, req.getDevSn()));
        if (ObjectUtil.isNull(cabinet)) {
            throw new ServiceException(CabinetExceptionEnum.CABINET_ISNOT_EXISTS);
        }

        //添加单警柜箱门信息默认状态为0正常
        List<String> boxNumList = req.getCabinetBoxList().stream().map(UpdateCabinetBoxReq::getId).collect(Collectors.toList());
        //判断是否绑定人员，如果绑定，则直接将人和箱门的关系进行解绑操作
        cabinetBoxPoliceService.remove(new LambdaQueryWrapper<CabinetBoxPolice>().in(CabinetBoxPolice::getCabinetBoxId,boxNumList));
        //判断该箱门下面是否有装备绑定，如果存在装备绑定，则直接将箱门解绑装备并且将对应epc所在的locationId赋值为空
        //不进行解绑操作，直接减库存以及将epc所在的位置进行赋值为空，并且将装备绑定状态设置为0--未绑定
        setInvOrSum(boxNumList, cabinet);

        remove(new LambdaQueryWrapper<CabinetBox>()
                .eq(CabinetBox::getCabinetId, cabinet.getId())
                .in(CabinetBox::getId, boxNumList));

        // 更新 Cabinet 实体的 num 字段
        Integer cabinetNum = cabinet.getNum();
        if (cabinetNum != null) {
            cabinet.setNum(Math.max(cabinetNum - boxNumList.size(),0));
            cabinetService.updateById(cabinet);
        }
        if (ObjectUtil.isNotEmpty(req.getActionFrom()) && req.getActionFrom().equals("platform")) {
            //请求来源于平台，则进行推送
            MQ.SendMsg("cabinetMsg", req.getDevSn(), "cabinetChange");
        }
        CabinetDto cabinetDto = new CabinetDto();
        BeanPlusUtil.copyProperties(cabinet,cabinetDto);
        List<CabinetBoxDto> collect = req.getCabinetBoxList().stream().map(cabinetBox -> {
                    CabinetBoxDto cabinetBoxDto = new CabinetBoxDto();
                    BeanPlusUtil.copyProperties(cabinetBox, cabinetBoxDto);
                    return cabinetBoxDto;
                }
        ).collect(Collectors.toList());
        cabinetDto.setCabinetBoxList(collect);
        return cabinetDto;
    }


    private Boolean setInvOrSum(List<String> boxNumList,Cabinet cabinet){

        //判断该箱门下面是否有装备绑定，如果存在装备绑定，则直接将箱门解绑装备并且将对应epc所在的locationId赋值为空
        //不进行解绑操作，直接减库存以及将epc所在的位置进行赋值为空，并且将装备绑定状态设置为0--未绑定
        List<Inventory> invList = inventoryService.list(new LambdaQueryWrapper<Inventory>().in(Inventory::getLocationId, boxNumList));
        List<WarehouseInventory> wareInvList = warehouseInventoryService.list(new LambdaQueryWrapper<WarehouseInventory>().in(WarehouseInventory::getLocationId, boxNumList));
        if (CollectionUtil.isNotEmpty(invList)){
            Map<String,Object[]> invSummaryMap=new HashMap<>();
            for (Inventory inventory:invList) {
                String key=inventory.getOrgId()+cabinet.getId()+inventory.getTypeId()+inventory.getSizeId()+inventory.getPrice()+inventory.getProperty();
                if (!invSummaryMap.containsKey(key)){
                    if (inventory.getLocationState().equals("in")){
                        Object[] item=new Object[]{inventory.getOrgId(),cabinet.getId(),inventory.getTypeId(),inventory.getSizeId(),inventory.getPrice(),inventory.getProperty(),1,0};
                        invSummaryMap.put(key,item);
                    }else {
                        Object[] item=new Object[]{inventory.getOrgId(),cabinet.getId(),inventory.getTypeId(),inventory.getSizeId(),inventory.getPrice(),inventory.getProperty(),0,1};
                        invSummaryMap.put(key,item);
                    }
                }else {
                    Object[] searchItem = invSummaryMap.get(key);
                    if (inventory.getLocationState().equals("in")){
                        searchItem[6]=(Integer)searchItem[6]+1;
                    }else {
                        searchItem[7]=(Integer)searchItem[7]+1;
                    }
                    invSummaryMap.put(key,searchItem);
                }
            }
            List<InventorySummary> invSumList = inventorySummaryMapper.selectSum(new ArrayList<>(invSummaryMap.values()));
            for (Object[] obj:invSummaryMap.values()) {
                for (InventorySummary is:invSumList) {
                    if (obj[2].equals(is.getTypeId())
                            && obj[3].equals(is.getSizeId()) && is.getUnitPrice().compareTo((BigDecimal) obj[4])==0 && obj[5].equals(is.getProperty())){
                        is.setStockNumber(is.getStockNumber()-(Integer) obj[6]);
                        is.setOutboundNumber(is.getStockNumber()-(Integer) obj[7]);
                        is.setNumber(is.getStockNumber()-(Integer) obj[6]-(Integer) obj[7]);
                        is.setPrice(is.getUnitPrice().multiply(BigDecimal.valueOf(is.getNumber())));
                        break;
                    }
                }
            }
            inventorySummaryService.updateBatchById(invSumList);

            //修改装备状态
            invList.forEach(s->{s.setLocationId(null);s.setEqsBindState(0);});
            wareInvList.forEach(s->{s.setLocationId(null);s.setLocationName(null);});
            inventoryService.updateBatchById(invList);
            warehouseInventoryService.updateBatchById(wareInvList);
        }
        return true;
    }


    //判断箱子信息是否存在
    @Override
    public CabinetBox CabinetBoxExist(String id) {
        CabinetBox cabinetBox = getById(id);
        if (ObjectUtil.isNull(cabinetBox)) {
            throw new ServiceException(CabinetBoxExceptionEnum.CABINETBOX_ISNOT_EXISTS);
        }
        return cabinetBox;
    }

    @Override
    public Cabinet getCabByBoxId(String locationId) {
        return cabinetBoxMapper.getCabByBoxId(locationId);
    }

    @Override
    public Boolean updateBoxInfo(UpdateCabinetBoxReq req) {
        CabinetBox cabinetBox = getById(req.getId());
        if (ObjectUtil.isNull(cabinetBox)) {
            throw new ServiceException(CabinetBoxExceptionEnum.CABINETBOX_ISNOT_EXISTS);
        }
        BeanPlusUtil.copyProperties(req,cabinetBox);
        return updateById(cabinetBox);
    }

}
