/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package com.youchain.businessdata.service.impl;

import com.youchain.basicdata.domain.Point;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.repository.CountMoveDetailRepository;
import com.youchain.businessdata.repository.InventoryRepository;
import com.youchain.businessdata.repository.XppRecordRepository;
import com.youchain.businessdata.service.*;
import com.youchain.businessdata.service.dto.CountMoveDetailRecordDto;
import com.youchain.exception.BadRequestException;
import com.youchain.modules.system.domain.Dept;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.CountMoveRepository;
import com.youchain.businessdata.service.dto.CountMoveDto;
import com.youchain.businessdata.service.dto.CountMoveQueryCriteria;
import com.youchain.businessdata.service.mapstruct.CountMoveMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;

import java.util.*;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;

/**
* @website https://eladmin.vip
* @description 服务实现
* @author houjianlan
* @date 2024-11-19
**/
@Service
@Slf4j
@RequiredArgsConstructor
public class CountMoveServiceImpl implements CountMoveService {

    private final CountMoveRepository countMoveRepository;
    private final CountMoveMapper countMoveMapper;
    private final InventoryRepository inventoryRepository;
    private final InventoryLogService inventoryLogService;
    private final InventoryService inventoryService;
    private final XppRecordRepository xppRecordRepository;
    private final XppRecordService xppRecordService;
    private final CountMoveDetailService countMoveDetailService;
    private final CountMoveDetailRecordService countMoveDetailRecordService;
    private final CountMoveDetailRepository countMoveDetailRepository;
    private final EntityManager entityManager;

    @Override
    public Map<String,Object> queryAll(CountMoveQueryCriteria criteria, Pageable pageable){
        Page<CountMove> page = countMoveRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder),pageable);
        return PageUtil.toPage(page.map(countMoveMapper::toDto));
    }

    @Override
    public List<CountMoveDto> queryAll(CountMoveQueryCriteria criteria){
        return countMoveMapper.toDto(countMoveRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public CountMoveDto findById(Long id) {
        CountMove countMove = countMoveRepository.findById(id).orElseGet(CountMove::new);
        ValidationUtil.isNull(countMove.getId(),"CountMove","id",id);
        return countMoveMapper.toDto(countMove);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CountMoveDto create(CountMove resources) {
        return countMoveMapper.toDto(countMoveRepository.save(resources));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(CountMove resources) {
        CountMove countMove = countMoveRepository.findById(resources.getId()).orElseGet(CountMove::new);
        ValidationUtil.isNull( countMove.getId(),"CountMove","id",resources.getId());
        countMove.copy(resources);
        countMoveRepository.save(countMove);
    }

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            countMoveRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<CountMoveDto> all, HttpServletResponse response) throws Exception {
        List<Map<String, Object>> list = ExcelDownUtils.CreateMap(all, "CountMove");
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void countCheck(CountMove countMove) {
        if(countMove.getDstPoint()==null){
            throw new BadRequestException(countMove.getCode() + "需填写目标库位");
        }
        List<Inventory> inventoryList=inventoryRepository.queryInventoryArea(countMove.getSrcArea().getId());
        for(Inventory inv:inventoryList) {
            ItemKey itemKey = inv.getItemKey();
            if(inv.getQueuedQty()>0){
                throw new BadRequestException(itemKey.getItem().getCode()+"包含占用数，不能移位");
            }
//            if(inv.getStockCode()==null) {//非箱单库存根据纳入数调整库存数
//                int nrs = xppRecordRepository.queryXppItemKeyPointNrs(itemKey.getId(), inv.getPoint().getId());
//                if (inv.getQueuedQty() > 0) {
//                    throw new BadRequestException(itemKey.getItem().getCode() + "包含占用数");
//                }
//                if (inv.getQuantity().intValue() != nrs) {
//                    inventoryLogService.storeInventoryLog(BizStatus.COUNT_MOVE, BizStatus.INVARIANT, countMove.getCode(), countMove.getDstArea(), itemKey, inv.getPoint(), inv.getPoint(), null, inv.getQuantity() + 0d, nrs + 0d, null,
//                            BizStatus.COUNT, null, inv.getId(), "调整库存数量，和现品票匹配");
//                    inv.setQuantity(nrs + 0d);
//                    inventoryService.update(inv);
//                }
//            }
            createCountDetail(countMove,inv,itemKey,countMove.getDstPoint());
        }

    }

    @Override
    public void createCountDetail(CountMove countMove,Inventory inv,ItemKey itemKey,Point dstPoint) {
        CountMoveDetail countMoveDetail=new CountMoveDetail();
        countMoveDetail.setStatus(BizStatus.OPEN);
        countMoveDetail.setCountMove(countMove);
        countMoveDetail.setInvId(inv.getId());
        countMoveDetail.setItemKey(itemKey);
        countMoveDetail.setSrcPoint(inv.getPoint());
        countMoveDetail.setOrderQty(inv.getQuantity());
        countMoveDetail.setCountQty(0d);
        countMoveDetail.setSrcStockCode(inv.getStockCode());//箱单号
        countMoveDetail.setDstPoint(dstPoint);
        countMoveDetailService.create(countMoveDetail);
        countMove.setOrderQty(countMove.getOrderQty()+inv.getQuantity());
        this.update(countMove);

    }
    static int iii_ok=0;

    public void countXpp2(CountMove countMove) {
        Dept dept=UserUtils.getDept();
        List<CountMoveDetail> countMoveDetailList=countMoveDetailRepository.queryDetails(countMove.getId());
        log.info("countMoveDetailList:"+countMoveDetailList.size());
        int i=0;
        for(CountMoveDetail d:countMoveDetailList){
            log.info(i+++"===="+new Date());
            List<Inventory> inventoryList=inventoryRepository.queryInventoryPointIk(d.getSrcPoint().getId(),d.getItemKey().getId());
            for(Inventory inv:inventoryList) {
                ItemKey itemKey = inv.getItemKey();
                List<XppRecord> xppRecordList = xppRecordRepository.queryXppItemKeyPoint(itemKey.getId(), inv.getPoint().getId());
                if (inv.getQueuedQty() > 0) {
                    throw new BadRequestException(itemKey.getItem().getCode() + "包含占用数");
                }
                log.info("现品票处理==="+i+"===="+new Date()+"===="+xppRecordList.size());
                for (XppRecord xpp : xppRecordList) {
                    xpp.setInvPoint(d.getDstPoint());
                    xpp.setCountCode(countMove.getCode());
                    xppRecordService.update(xpp);
                    inventoryLogService.storeInventoryLog(BizStatus.COUNT_MOVE, BizStatus.REDUCE, countMove.getCode(), inv.getArea(), itemKey,d.getSrcPoint(), d.getDstPoint(), inv.getZzkw(), xpp.getNrs() + 0d, xpp.getNrs() + 0d, xpp.getEwm(),
                            BizStatus.COUNT, xpp.getId(), inv.getId(), "盘点移位"+d.getDstPoint().getArea().getCode());
                    d.setCountQty(d.getCountQty()+xpp.getNrs());
                    countMoveDetailService.update(d);
                    CountMoveDetailRecord countMoveDetailRecord=new CountMoveDetailRecord();
                    countMoveDetailRecord.setCountMove(countMove);
                    countMoveDetailRecord.setCountMoveDetail(d);
                    countMoveDetailRecord.setXppEwm(xpp.getEwm());
                    countMoveDetailRecord.setCountQty(xpp.getNrs()+0d);
                    countMoveDetailRecord.setXpp(xpp);
                    countMoveDetailRecord.setSrcPoint(d.getSrcPoint());
                    countMoveDetailRecord.setCountPoint(d.getDstPoint());
                    countMoveDetailRecord.setItemKey(d.getItemKey());
                    countMoveDetailRecord.setStatus(BizStatus.OPEN);
                    countMoveDetailRecordService.create(countMoveDetailRecord);
                    //查找目标库位是否有库存，有则数量累加，没有新建
                    Inventory newInv=inventoryService.getInventory(itemKey,d.getDstPoint().getArea(),d.getDstPoint(),inv.getZzkw(),dept,BizStatus.COUNT_MOVE,null);
                    newInv.setQuantity(newInv.getQuantity()+xpp.getNrs());
                    inventoryService.update(newInv);
                    inv.setQuantity(inv.getQuantity()-xpp.getNrs());
                    inventoryService.update(inv);
                }

            }
        }
        countMove.setStatus(BizStatus.COUNT_ALL);
        this.update(countMove);
    }

    @Override
    public void countXpp(CountMove countMove) {
        Long st_time=System.currentTimeMillis();
        Dept dept=UserUtils.getDept();

        List<CountMoveDetail> countMoveDetailCount=countMoveDetailRepository.queryDetails(countMove.getId());
        log.info("countMoveDetailList:"+countMoveDetailCount.size());


        List<Object[]> countMoveDetailObjs=countMoveDetailRepository.queryIkPGroupDetails(countMove.getId());
        log.info("countMoveDetailList:"+countMoveDetailObjs.size());

        //得到盘点库区下所有库存
        String point_type=BaseStatus.CH;
        if(countMove.getSrcArea().getBexb()){
            point_type=BaseStatus.ZZKW;
        }
        List<Inventory> inventoryListAll=inventoryRepository.queryInventoryArea2(countMove.getSrcArea().getId(),point_type);
        log.info("inventoryListAll:"+inventoryListAll.size());
        Map<String,List<Inventory>> map_inventory=new HashMap<>();
        for (Inventory inv :inventoryListAll ) {
            //同一itemKey，库位，箱单号数据合并
            String key=inv.getItemKey().getId()+""+inv.getPoint().getId();
            if(inv.getStockCode()!=null){
                key+=inv.getStockCode();
            }
            List<Inventory> ll=map_inventory.get(key);
            if(ll!=null && ll.size()>0){
                ll.add(inv);
                map_inventory.put(key,ll);
            }else{
                List<Inventory> list_aa=new ArrayList<>();
                list_aa.add(inv);
                map_inventory.put(key,list_aa);
            }
        }
        log.info("map_inventory:"+map_inventory.keySet().size());

        log.info("xppRecordListAll:");
        List<XppRecord> xppRecordListAll = new ArrayList<>();
        if(!countMove.getSrcArea().getBexb()) {
            xppRecordListAll= xppRecordRepository.queryXppItemKeyPoint2();
        }
        Map<String,List<XppRecord>> map_xppRecord=new HashMap<>();
        log.info("xppRecordListAll:"+xppRecordListAll.size());
        for (XppRecord xpp :xppRecordListAll ) {
            String key=xpp.getItemKey().getId()+""+xpp.getInvPoint().getId();
            List<XppRecord> ll=map_xppRecord.get(key);
            if(ll!=null && ll.size()>0){
                ll.add(xpp);
                map_xppRecord.put(key,ll);
            }else{
                List<XppRecord> list_aa=new ArrayList<>();
                list_aa.add(xpp);
                map_xppRecord.put(key,list_aa);
            }
        }
        log.info("map_xppRecord:"+map_xppRecord.keySet().size());



         iii_ok=0;

        for(Object[] objs:countMoveDetailObjs){
            Long itemKeyId=Long.parseLong(objs[1].toString());
            Long dstPointId=Long.parseLong(objs[2].toString());
            String stock_code=objs[3]==null?null:objs[3].toString();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    List<CountMoveDetail> countMoveDetailList=countMoveDetailRepository.queryIkPDetails(countMove.getId(),itemKeyId,dstPointId,stock_code);
                    for (CountMoveDetail d:countMoveDetailList){
                    //log.info(++iii +"");
                    String key1=d.getItemKey().getId()+""+d.getSrcPoint().getId();
                    if(stock_code!=null){
                        key1+=stock_code;
                    }
                    List<Inventory> inventoryList=new ArrayList<>();
                    if(map_inventory!=null&&map_inventory.size()>0) {
                        inventoryList=map_inventory.get(key1);
                    }
                    //log.info("Inventory======="+new Date()+"====");
                    for(Inventory inv:inventoryList) {
                        ItemKey itemKey = inv.getItemKey();
                        String key2 = itemKey.getId() + "" + inv.getPoint().getId();
                        if(inv.getStockCode()!=null){
                            key2+=inv.getStockCode();
                        }
                        if (inv.getQueuedQty() > 0) {
                            //throw new BadRequestException(itemKey.getItem().getCode() + "包含占用数");
                            d.setRemark("包含占用数,不能移位！");
                            countMoveDetailRepository.save(d);
                            continue;
                        }

                        List<XppRecord> xppRecordList =new ArrayList<>();
                        if(map_xppRecord!=null&&map_xppRecord.size()>0) {
                            xppRecordList=map_xppRecord.get(key2);
                        }
                            //log.info("XppRecord=======" + new Date() + "====");

                            //log.info("现品票处理===" + iii + "====" + new Date() + "====" + xppRecordList.size());
                        if(xppRecordList!=null&&xppRecordList.size()>0) {
                            for (XppRecord xpp : xppRecordList) {
                                xpp.setInvPoint(d.getDstPoint());
                                xpp.setArea(d.getDstPoint().getArea());
                                xpp.setCountCode(countMove.getCode());
                                xppRecordService.update(xpp);
                                inventoryLogService.storeInventoryLog(BizStatus.COUNT_MOVE, BizStatus.REDUCE, countMove.getCode(), inv.getArea(), itemKey, d.getSrcPoint(), d.getDstPoint(), inv.getZzkw(), xpp.getNrs() + 0d, xpp.getNrs() + 0d, xpp.getEwm(),
                                        BizStatus.COUNT, xpp.getId(), inv.getId(), "盘点移位" + d.getDstPoint().getArea().getCode());
                                d.setCountQty(d.getCountQty() + xpp.getNrs());
                                countMoveDetailService.update(d);
                                createCountMoveDetailRecord(countMove,d,xpp);
                                //查找目标库位是否有库存，有则数量累加，没有新建
                                Inventory newInv = inventoryService.getInventory(itemKey, d.getDstPoint().getArea(), d.getDstPoint(), inv.getZzkw(), dept, BizStatus.COUNT_MOVE, null);
                                newInv.setQuantity(newInv.getQuantity() + xpp.getNrs());
                                inventoryService.update(newInv);
                                inv.setQuantity(inv.getQuantity() - xpp.getNrs());
                                inventoryService.update(inv);
                                countMove.setCountQty(countMove.getCountQty()+d.getCountQty());
                            }
                        }else{
                            d.setCountQty(d.getCountQty() + d.getOrderQty());
                            countMoveDetailService.update(d);
                            createCountMoveDetailRecord(countMove,d,null);
                            //查找目标库位是否有库存，有则数量累加，没有新建
                            Inventory newInv = inventoryService.getInventory(itemKey, d.getDstPoint().getArea(), d.getDstPoint(), inv.getZzkw(), dept, BizStatus.COUNT_MOVE, d.getSrcStockCode());
                            newInv.setQuantity(newInv.getQuantity() + d.getOrderQty());
                            inventoryService.update(newInv);
                            inv.setQuantity(inv.getQuantity() - d.getOrderQty());
                            inventoryService.update(inv);
                        }
                    }
                    log.info(++iii_ok +"");
                    }
                }
            }).start();

            try{
                Thread.sleep(100);
            }catch (Exception e){

            }

        }

        while(countMoveDetailCount.size()!=iii_ok && System.currentTimeMillis()-st_time<(1000*60*5)){
            try{
                Thread.sleep(1000);
            }catch (Exception e){

            }

            continue;
        }
        countMove.setStatus(BizStatus.COUNT_ALL);
        this.update(countMove);
    }

    CountMoveDetailRecordDto createCountMoveDetailRecord(CountMove countMove,CountMoveDetail d,XppRecord xpp){
        CountMoveDetailRecord countMoveDetailRecord = new CountMoveDetailRecord();
        countMoveDetailRecord.setCountMove(countMove);
        countMoveDetailRecord.setCountMoveDetail(d);
        if(xpp!=null) {
            countMoveDetailRecord.setXppEwm(xpp.getEwm());
            countMoveDetailRecord.setCountQty(xpp.getNrs() + 0d);
            countMoveDetailRecord.setXpp(xpp);
        }else{
            countMoveDetailRecord.setCountQty(d.getCountQty());
        }
        countMoveDetailRecord.setSrcPoint(d.getSrcPoint());
        countMoveDetailRecord.setCountPoint(d.getDstPoint());
        countMoveDetailRecord.setItemKey(d.getItemKey());
        countMoveDetailRecord.setStatus(BizStatus.OPEN);
        countMoveDetailRecord.setSrcStockCode(d.getSrcStockCode());
        countMove.setCountQty(countMove.getCountQty()+countMoveDetailRecord.getCountQty());
        return countMoveDetailRecordService.create(countMoveDetailRecord);
    }
}