package com.sw.mes.store.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sw.mes.core.api.system.YbFeignClients;
import com.sw.mes.core.dto.MaterialModelDto;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.utils.DynmaicQueryWrapper;
import com.sw.mes.core.utils.RequestPage;
import com.sw.mes.store.dto.AvailableInventoryDto;
import com.sw.mes.store.dto.WarehouseInventoryDto;
import com.sw.mes.store.entity.WarehouseInventory;
import com.sw.mes.store.entity.WarehouseMaterial;
import com.sw.mes.store.entity.WarehouseModel;
import com.sw.mes.store.entity.WarehouseQueryParam;
import com.sw.mes.store.mapper.WarehouseInventoryMapper;
import com.sw.mes.store.service.WarehouseInventoryService;
import com.sw.mes.store.service.WarehouseMaterialService;
import com.sw.mes.store.service.WarehouseModelService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.servlet.ServletRequest;
import java.math.BigDecimal;
import java.util.*;


/**
 * @Author
 * @Description：
 * @Date: Create in
 * @Modified By:
 */
@Service
@Transactional
public class WarehouseInventoryServiceImpl extends ServiceImpl<WarehouseInventoryMapper, WarehouseInventory> implements WarehouseInventoryService {

    @Autowired
    WarehouseInventoryMapper inventoryMapper;

    @Autowired
    private WarehouseMaterialService warehouseMaterialService;
    @Autowired
    private YbFeignClients ybFeignClients;
    @Autowired
    private WarehouseModelService warehouseModelService;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public WarehouseInventory getByUniqueCode(String uniqueCode) {
        return inventoryMapper.getByUniqueCode(uniqueCode);
    }

    @Override
    public List<WarehouseInventory> getByBatchNo(String batchNo) {
        return inventoryMapper.getByBatchNo(batchNo);
    }

    @Override
    public List<WarehouseInventory> getByBatchNoAndMaterialCodes(String batchNo, List<String> materialCodes) {
        return inventoryMapper.getByBatchNoAndMaterialCodes(batchNo, materialCodes);
    }

    @Override
    public WarehouseInventory getByMaterialAndWarehouse(Long materialId, Long warehouseId) {
        return inventoryMapper.getByMaterialAndWarehouse(materialId, warehouseId);
    }

    @Override
    public List<WarehouseInventory> getByWarehouseId(Long warehouseId) {
        return inventoryMapper.getByWarehouseId(warehouseId);
    }

    @Override
    public List<WarehouseInventory> getByWarehouseIds(List<Long> typeIds) {
        return inventoryMapper.getByWarehouseIds(typeIds);
    }

    @Override
    public List<WarehouseInventory> getByMaterialAndBatchNoAndWarehouseId(String batchNo, String materialModelCode, Long warehouseId) {
        return inventoryMapper.getByMaterialAndBatchNoAndWarehouseId(batchNo, materialModelCode, warehouseId);
    }

    @Override
    public List<WarehouseInventory> getByMaterialAndBatchNoAndWarehouseCode(String batchNo, String materialModelCode, String warehouseCode) {
        return inventoryMapper.getByMaterialAndBatchNoAndWarehouseCode(batchNo, materialModelCode, warehouseCode);
    }

    @Override
    public List<WarehouseInventory> getByMaterialAndBatchNoAndWarehouseCodes(String batchNo, String materialModelCode, String warehouseCode) {
        return inventoryMapper.getByMaterialAndBatchNoAndWarehouseCodes(batchNo, materialModelCode, warehouseCode);
    }

    @Override
    public Page<WarehouseInventory> groupByMaterial(ServletRequest request, RequestPage page) {
        WarehouseQueryParam param = new WarehouseQueryParam();
        param.setMaterialName(request.getParameter("search_LIKE_materialName"));
        param.setMaterialCode(request.getParameter("search_LIKE_materialCode"));
        String searchInWarehouseModelId = request.getParameter("search_IN_warehouseModelId");
        if (StringUtils.isNotBlank(searchInWarehouseModelId)) {
            String[] split = searchInWarehouseModelId.split(",");
            param.setWarehouseModelId(Arrays.asList(split));
        }
        param.setMaterialTypeName(request.getParameter("search_LIKE_materialTypeName"));
        param.setBatchNo(request.getParameter("search_EQ_batchNo"));
        param.setUniqueCode(request.getParameter("search_EQ_uniqueCode"));

        //条件查询
        Page<WarehouseInventory> iPage = new Page<>(page.getPage(), page.getRows());
        Page<WarehouseInventory> warehouseInventoryIPage = inventoryMapper.groupByMaterial(iPage, param);
        long total = warehouseInventoryIPage.getTotal();
        List<WarehouseInventory> records = warehouseInventoryIPage.getRecords();
        if (CollectionUtils.isNotEmpty(records)) {
            //根据物料分组，查询所有库位下的库存总数
            if (StringUtils.isBlank(searchInWarehouseModelId)) {//fixme 估计是有问题的，先不动了
                records.forEach(e -> e.setTotalQuantity(e.getQuantity()));
            } else {
                WarehouseQueryParam queryParam = new WarehouseQueryParam();
                List<Long> materials = new ArrayList<>();
                records.forEach(e -> materials.add(e.getMaterialModelId()));
                queryParam.setMaterialIds(materials);
                Page<WarehouseInventory> warehouseInventoryIPages = inventoryMapper.groupByMaterial(iPage, queryParam);
                List<WarehouseInventory> records1 = warehouseInventoryIPages.getRecords();
                Map<String, String> cache = new HashMap<>();
                for (WarehouseInventory record : records) {
                    for (WarehouseInventory inventory : records1) {
                        if (record.getMaterialModelId().equals(inventory.getMaterialModelId())) {
                            if (null == record.getTotalQuantity()) {//如果为空，则是首次set
                                record.setTotalQuantity(inventory.getQuantity());
                            } else {
                                record.setTotalQuantity(record.getTotalQuantity().add(inventory.getQuantity()));
                            }
                        }
                        //做一个cache保护一下
                        if (cache.containsKey(inventory.getMaterialModelCode())) {
                            inventory.setMaterialCategoryName(cache.get(inventory.getMaterialModelCode()));
                            continue;
                        }
                        if (com.sw.mes.core.utils.StringUtils.isNotEmpty(inventory.getMaterialModelCode())) {
                            Result<MaterialModelDto> materialByCode = ybFeignClients.getMaterialByCode(inventory.getMaterialModelCode());
                            if (materialByCode.getCode().equals(200) && !ObjectUtils.isEmpty(materialByCode.getData())) {
                                inventory.setMaterialCategoryName(materialByCode.getData().getMaterialTypeDto().getName());
                                cache.put(inventory.getMaterialModelCode(), materialByCode.getData().getMaterialTypeDto().getName());
                            }
                        }
                    }
                }
            }
        }
        //fix 这一步有引用丢失的问题，要么直接后面重新set，要么这边不要拿出来
        warehouseInventoryIPage.setRecords(records);
        warehouseInventoryIPage.setTotal(total);
        return warehouseInventoryIPage;
    }

    @Override
    public List<WarehouseInventory> findAllWarehouseInventory(ServletRequest request) {
        WarehouseQueryParam param = new WarehouseQueryParam();
        param.setMaterialName(request.getParameter("search_LIKE_materialName"));
        param.setMaterialCode(request.getParameter("search_LIKE_materialCode"));
        String searchInWarehouseModelId = request.getParameter("search_IN_warehouseModelId");
        if (StringUtils.isNotBlank(searchInWarehouseModelId)) {
            String[] split = searchInWarehouseModelId.split(",");
            param.setWarehouseModelId(Arrays.asList(split));
        }
        param.setMaterialTypeName(request.getParameter("search_LIKE_materialTypeName"));
        param.setBatchNo(request.getParameter("search_EQ_batchNo"));
        param.setUniqueCode(request.getParameter("search_EQ_uniqueCode"));
        List<WarehouseInventory> allWarehouseInventory = inventoryMapper.findAllWarehouseInventory(param);
        return allWarehouseInventory;
    }

    @Override
    public Map<String, BigDecimal> getQuantity(List<WarehouseInventoryDto> inventoryDtos) {
        if (CollectionUtils.isEmpty(inventoryDtos)) {
            throw new BusinessException("库存对象为空，请检查数据！");
        }
        Map<String, BigDecimal> result = new HashMap<>(inventoryDtos.size());
        for (WarehouseInventoryDto inventoryDto : inventoryDtos) {
            Long materialModelId = inventoryDto.getMaterialModelId();
            Long warehouseId = inventoryDto.getWarehouseId();
            if (materialModelId == null || materialModelId == 0) {
                throw new BusinessException("库存对象物料为空，请检查数据！");
            }
            if (warehouseId == null || warehouseId == 0) {
                throw new BusinessException("库存对象库位为空，请检查数据！");
            }
            String uniqueCode = inventoryDto.getUniqueCode();
            String batchNo = inventoryDto.getBatchNo();
            if (StringUtils.isNotBlank(uniqueCode)) {
                WarehouseInventory byUniqueCode = inventoryMapper.getByUniqueCode(uniqueCode);
                result.put(uniqueCode, byUniqueCode.getQuantity());
            } else {
                List<WarehouseInventory> warehouseInventory = inventoryMapper.getByMaterialAndBatchNoAndWarehouseId(batchNo, inventoryDto.getMaterialModelCode(), warehouseId);
                if (CollectionUtils.isNotEmpty(warehouseInventory)) {
                    String key = StringUtils.isBlank(batchNo) ? materialModelId + "-" + warehouseId + "" : batchNo + "-" + materialModelId + "-" + warehouseId;
                    result.put(key, warehouseInventory.get(0).getQuantity());
                }
            }
        }
        return result;
    }

    @Override
    public List<WarehouseInventory> getByScanCode(String scanCode) {
        if (StringUtils.isBlank(scanCode)) {
            throw new BusinessException("扫描结果为空！");
        }
        List<WarehouseInventory> inventories = new ArrayList<>();
        //扫描的结果可能是 唯一码或批次号或物料条码
        //假设扫描结果是唯一码，则根据唯一码查询
        WarehouseInventory byUniqueCode = inventoryMapper.getByUniqueCode(scanCode);
        if (byUniqueCode != null) {
            inventories.add(byUniqueCode);
        } else {
            //假设扫描结果是批次号，则根据批次号查询
            List<WarehouseInventory> byBatchNoAndMaterialCodes = inventoryMapper.getByBatchNo(scanCode);
            if (CollectionUtils.isNotEmpty(byBatchNoAndMaterialCodes)) {
                inventories.addAll(byBatchNoAndMaterialCodes);
            } else {
                //假设扫描结果是物料号，根据物料号查询
                List<WarehouseInventory> byMaterialCode = inventoryMapper.getByMaterialCode(scanCode);
                if (CollectionUtils.isNotEmpty(byMaterialCode)) {
                    inventories.addAll(byMaterialCode);
                } else {
                    throw new BusinessException("扫描的库存料号：" + scanCode + "库存数据不存在，请重新选择！");
                }
            }
        }
        return inventories;
    }

    @Override
    public List<WarehouseInventory> getByMaterialCode(String materialModelCode) {
        return inventoryMapper.getByMaterialCode(materialModelCode);
    }

    @Override
    public List<WarehouseInventory> getByMaterialAndBatchNo(String batchNo, String materialCode) {
        return inventoryMapper.getByMaterialAndBatchNo(batchNo, materialCode);
    }

    @Override
    public Page<WarehouseInventory> listByPage(ServletRequest request, RequestPage requestPage) {
        QueryWrapper<WarehouseInventory> queryWrapper = DynmaicQueryWrapper.searchFilter(request, WarehouseInventory.class);
        queryWrapper.eq("del", 0);
        Page<WarehouseInventory> page = this.page(new Page<>(requestPage.getPage(), requestPage.getRows()), queryWrapper);
        List<WarehouseInventory> records = page.getRecords();
        if (CollectionUtils.isNotEmpty(records)) {
            //根据物料分组，查询所有库位下的库存总数
            WarehouseQueryParam queryParam = new WarehouseQueryParam();
            List<Long> materials = new ArrayList<>();
            records.forEach(e -> materials.add(e.getMaterialModelId()));
            queryParam.setMaterialIds(materials);
            IPage<WarehouseInventory> warehouseInventoryIPages = inventoryMapper.groupByMaterial(new Page<>(1, requestPage.getRows()), queryParam);
            List<WarehouseInventory> records1 = warehouseInventoryIPages.getRecords();
            for (WarehouseInventory record : records) {
                for (WarehouseInventory inventory : records1) {
                    if (record.getMaterialModelId().equals(inventory.getMaterialModelId())) {
                        record.setTotalQuantity(inventory.getQuantity());
                    }
                }
            }
        }
        return page;
    }

    /**
     * @return
     * @Author wupeng
     * @Description 更新库存
     * @Date 14:21 2023/11/21
     * @Param type=1入库，type=2出库
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateInventory(WarehouseInventory inventory, Integer type) {
//        String lockKey = new String();
//        //唯一码存在
//        if (StringUtils.isNotBlank(inventory.getUniqueCode())) {
//            WarehouseModel warehouseModel = warehouseModelService.getById(inventory.getWarehouseId());
//            if (StringUtils.isNotBlank(warehouseModel.getCode())) {
//                lockKey = inventory.getMaterialModelCode() + warehouseModel.getCode() + inventory.getUniqueCode();
//            } else {
//                throw new BusinessException("未查询到【" + inventory.getWarehouseId() + "】库位信息!");
//            }
//        } else if (StringUtils.isEmpty(inventory.getUniqueCode()) && StringUtils.isNotBlank(inventory.getBatchNo())) {
//            //唯一码不存在,用批次号
//            WarehouseModel warehouseModel = warehouseModelService.getById(inventory.getWarehouseId());
//            if (StringUtils.isNotBlank(warehouseModel.getCode())) {
//                lockKey = inventory.getMaterialModelCode() + warehouseModel.getCode() + inventory.getBatchNo();
//            } else {
//                throw new BusinessException("未查询到【" + inventory.getWarehouseId() + "】库位信息!");
//            }
//        }else if(StringUtils.isEmpty(inventory.getUniqueCode()) && StringUtils.isEmpty(inventory.getBatchNo())){
//            WarehouseModel warehouseModel = warehouseModelService.getById(inventory.getWarehouseId());
//            if (StringUtils.isNotBlank(warehouseModel.getCode())) {
//                lockKey = inventory.getMaterialModelCode() + warehouseModel.getCode();
//            } else {
//                throw new BusinessException("未查询到【" + inventory.getWarehouseId() + "】库位信息!");
//            }
//        }
//        RLock lock = RedissonUtils.getRLock(redissonClient, lockKey);
//        boolean isLock = RedissonUtils.getRLockExpireTime(lock, 6L, 6L);
//        if (isLock) {
//            try {
//                lock.lock();
        LambdaUpdateWrapper<WarehouseInventory> updateWrapper = new LambdaUpdateWrapper();
        updateWrapper.eq(WarehouseInventory::getId, inventory.getId());
        if (type == 2) {
            //出库时加上库存大于0的条件
            updateWrapper.gt(WarehouseInventory::getQuantity, 0);
            //当库存为0时，逻辑删除
            updateWrapper.set(WarehouseInventory::getDel, inventory.getDel());
        }
        updateWrapper.set(WarehouseInventory::getQuantity, inventory.getQuantity());
        this.update(inventory, updateWrapper);
//                this.saveOrUpdate(inventory);
        //查询是否配置了线边仓物料模型，设置安全库存。如果是先入库，后添加的配置，则需要把安全库存字段补足
        WarehouseMaterial warehouseMaterial = warehouseMaterialService.getByMaterialId(inventory.getMaterialModelId());
        if (warehouseMaterial != null) {
//                    //查询物料的所有库存数据
//                    List<WarehouseInventory> warehouseInventories = this.getByMaterialCode(inventory.getMaterialModelCode());
//                    for (WarehouseInventory warehouseInventory : warehouseInventories) {
//                        String safetyStock = warehouseInventory.getSafetyStock();
//                        if (StringUtils.isNotBlank(safetyStock)) {
//                            continue;
//                        }
//                        warehouseInventory.setSafetyStock(warehouseMaterial.getLowerLimit() + "-" + warehouseMaterial.getUpperLimit());
//                        warehouseInventory.setResidenceTime(warehouseMaterial.getResidenceTime());
//                        warehouseInventory.setTimeUnit(warehouseMaterial.getTimeUnit());
//                    }
//                    this.saveOrUpdateBatch(warehouseInventories);
            String safetyStock = warehouseMaterial.getLowerLimit() + "-" + warehouseMaterial.getUpperLimit();
            Integer residenceTime = warehouseMaterial.getResidenceTime();
            String timeUnit = warehouseMaterial.getTimeUnit();
            String materialModelCode = inventory.getMaterialModelCode();
            this.updateSafetyStockAndResidenceTimeAndTimeUnitByMaterialCode(safetyStock, residenceTime, timeUnit, materialModelCode);
        }
//            } finally {
//                if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
//                    lock.unlock();
//                    RedisTools.deleteObject(lockKey);
//                }
//            }
//        } else {
//            throw new BusinessException("有其他人正在操作，请稍后再试！");
//        }
    }

    @Override
    public List<AvailableInventoryDto> getAvailableInventorys(List<String> materialCodes) {
        return inventoryMapper.getAvailableInventorys(materialCodes);
    }

    @Override
    public WarehouseInventory getByBatchWarehouseId(String batchNo, Long warehouseId) {
        return inventoryMapper.getByBatchWarehouseId(batchNo, warehouseId);
    }

    @Override
    public WarehouseInventory getByBatchWarehouseCode(String batchNo, String warehouseCode) {
        return inventoryMapper.getByBatchWarehouseCode(batchNo, warehouseCode);
    }

    @Override
    public void updateSafetyStockAndResidenceTimeAndTimeUnitByMaterialCode(String safetyStock, Integer residenceTime, String timeUnit, String materialModelCode) {
        inventoryMapper.updateSafetyStockAndResidenceTimeAndTimeUnitByMaterialCode(safetyStock, residenceTime, timeUnit, materialModelCode);
    }

    @Override
    public List<String> getUniqueCodesByBatchNo(String batchNo) {
        return inventoryMapper.getUniqueCodesByBatchNo(batchNo);
    }

    @Override
    public List<String> findBatchNoBySerialNoOrTraceId(String serialNo, String traceId) {
        return inventoryMapper.findBatchNoBySerialNoOrTraceId(serialNo, traceId);
    }

    @Override
    public List<WarehouseInventoryDto> findWarehouseInventoryByMaterialCode(String materialCode) {
        List<WarehouseInventoryDto> warehouseInventoryDtos = new ArrayList<>();
        List<WarehouseInventory> warehouseInventoryByMaterialCode = inventoryMapper.findWarehouseInventoryByMaterialCode(materialCode);
        warehouseInventoryByMaterialCode.forEach(entity -> {
            WarehouseInventoryDto warehouseInventoryDto = new WarehouseInventoryDto();
            BeanUtils.copyProperties(entity, warehouseInventoryDto);
            warehouseInventoryDtos.add(warehouseInventoryDto);
        });
        return warehouseInventoryDtos;
    }

    @Override
    public WarehouseInventory getByCrystalNo(String crystalNo) {
        return inventoryMapper.getByCrystalNo(crystalNo);
    }
}