/*
*  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 cn.hutool.core.bean.BeanUtil;
import com.youchain.basicdata.domain.Box;
import com.youchain.basicdata.domain.Item;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.basicdata.repository.BoxRepository;
import com.youchain.basicdata.service.dto.ItemSmallDto;
import com.youchain.businessdata.domain.AgvTask;
import com.youchain.businessdata.domain.Inventory;
import com.youchain.businessdata.domain.PickDetail;
import com.youchain.businessdata.domain.Task;
import com.youchain.businessdata.repository.AgvTaskRepository;
import com.youchain.businessdata.repository.InventoryRepository;
import com.youchain.businessdata.repository.TaskRepository;
import com.youchain.modules.system.domain.Dept;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.PickDetailRepository;
import com.youchain.businessdata.service.PickDetailService;
import com.youchain.businessdata.service.dto.PickDetailDto;
import com.youchain.businessdata.service.dto.PickDetailQueryCriteria;
import com.youchain.businessdata.service.mapstruct.PickDetailMapper;
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.List;
import java.util.Map;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.LinkedHashMap;

/**
* @website https://eladmin.vip
* @description 服务实现
* @author huojin
* @date 2023-08-16
**/
@Service
@RequiredArgsConstructor
public class PickDetailServiceImpl implements PickDetailService {

    private final PickDetailRepository pickDetailRepository;
    private final PickDetailMapper pickDetailMapper;
    private final InventoryRepository inventoryRepository;
    private final BoxRepository boxRepository;
    private final AgvTaskRepository agvTaskRepository;
    private final TaskRepository taskRepository;


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

    @Override
    public List<PickDetailDto> queryAll(PickDetailQueryCriteria criteria){
        return pickDetailMapper.toDto(pickDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public PickDetailDto findById(Long id) {
        PickDetail pickDetail = pickDetailRepository.findById(id).orElseGet(PickDetail::new);
        ValidationUtil.isNull(pickDetail.getId(),"PickDetail","id",id);
        return pickDetailMapper.toDto(pickDetail);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PickDetailDto create(PickDetail resources) {
        return pickDetailMapper.toDto(pickDetailRepository.save(resources));
    }

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

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

    @Override
    public void download(List<PickDetailDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        int i=1;
        for (PickDetailDto pickDetail : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("序号",i++);
            map.put("任务号", pickDetail.getPo());
            map.put("物料编码", pickDetail.getItem().getCode());
            map.put("物料名称", pickDetail.getItem().getName());
            map.put("状态", pickDetail.getStatus());
            map.put("订单数量", pickDetail.getOrderQty());
            map.put("分配数量", pickDetail.getAllocatedQty());
            map.put("拣货数量", pickDetail.getPickedQty());
            map.put("备注", pickDetail.getRemark());
            map.put("创建人", pickDetail.getCreateBy());
            map.put("创建时间", pickDetail.getCreateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void allocate(long id,double quantity) throws Exception {
            PickDetailDto pickDetailDto=findById(id);
            PickDetail pd= toEntity(pickDetailDto);//Dto转实体
            ItemSmallDto itemSmallDto=pickDetailDto.getItem();
            Item item=BeanUtil.copyProperties(itemSmallDto,Item.class);//Dto转实体
            Dept dept=item.getDept();//仓库
            Box box =boxRepository.getBoxByItem(item.getId());
            Point endPoint=box.getPoint();//目标点位
            if(pd.getOrderQty()>pd.getAllocatedQty()){
                List<Inventory> Inventorys=inventoryRepository.queryInventory(item.getId());
                if(Inventorys.size()>0){
                    double allocateQty=0;
                    double unQty =quantity;//未分配数量
                    for(Inventory inv : Inventorys){
                       Stock stock= inv.getStock();//容器
                        Point startPoint=inv.getPoint();//起始点位
                        if (unQty == 0) {
                            break;
                        }
                        allocateQty = inv.getQuantity()- inv.getQueuedQty();//库存可用数量
                        if(allocateQty<=0){
                            continue;
                        }
                        if (unQty < allocateQty) {
                            allocateQty = unQty;
                        }
                        inv.setQueuedQty(inv.getQueuedQty()+allocateQty);
                        inventoryRepository.save(inv);
                        unQty -= allocateQty;
                        pd.setAllocatedQty(pd.getAllocatedQty()+ allocateQty);
                        if(pd.getOrderQty().equals(pd.getAllocatedQty())){
                            pd.setStatus(BizStatus.ALLOCATE);
                        }
                        pickDetailRepository.save(pd);

                        //生成搬运任务
                        AgvTask agvTask=new AgvTask(BizStatus.PICK,stock.getCode(),stock.getStockType().getCode(),startPoint.getCode(),endPoint.getCode(),startPoint.getCode(), BizStatus.OPEN,"01");
                        agvTaskRepository.save(agvTask);
                        //生成Task
                        Task task=new Task();
                        task.setItem(item);
                        task.setItemKey(inv.getItemKey());
                        task.setPickDetail(pd);
                        task.setBillCode(pd.getPo());
                        task.setSrcStock(inv.getStock());
                        task.setDstStock(inv.getStock());
                        task.setSrcPoint(startPoint);
                        task.setDstPoint(endPoint);
                        task.setSrcStockCode(inv.getStock().getCode());
                        task.setSrcPointCode(startPoint.getCode());
                        task.setDstPointCode(endPoint.getCode());
                        task.setInvStatus(inv.getStatus());
                        task.setTaskStatus(BizStatus.OPEN);
                        task.setPlanQty(allocateQty);
                        task.setInvId(inv.getId());
                        task.setDept(dept);
                        task.setAgvTask(agvTask);
                        taskRepository.save(task);
                    }
                }

            }else{
                throw new RuntimeException("已分配,请勿重复操作！");
            }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void cancelAllocate(long id,double quantity) throws Exception {

            PickDetailDto pickDetailDto=findById(id);
            PickDetail pd= toEntity(pickDetailDto);
            List<Task> Tasks= taskRepository.getPickNotAllTask(id);
            for(Task task:Tasks){
                //根据Taskz找到对应的库存
                Inventory inv = inventoryRepository.findById(task.getInvId()).get();
                inv.setQueuedQty(inv.getQueuedQty()-pd.getAllocatedQty());
                inventoryRepository.save(inv);

                //删除Task
                taskRepository.delete(task);

                pd.setAllocatedQty(pd.getAllocatedQty()-quantity);
                if(pd.getAllocatedQty()==0){
                    pd.setStatus(BizStatus.OPEN);
                }
                pickDetailRepository.save(pd);

            }

        }

    @Override
    public long count() {
       return pickDetailRepository.count();
    }

    @Override
    public PickDetail toEntity(PickDetailDto pickDetailDto) {
        return pickDetailMapper.toEntity(pickDetailDto);
    }

}
