/*
*  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.Area;
import com.youchain.basicdata.domain.AutomaticPlanDetail;
import com.youchain.basicdata.domain.BomAccount;
import com.youchain.basicdata.repository.AreaRepository;
import com.youchain.basicdata.repository.AutomaticPlanDetailRepository;
import com.youchain.basicdata.repository.BomAccountRepository;
import com.youchain.basicdata.service.AreaService;
import com.youchain.basicdata.service.BomAccountService;
import com.youchain.businessdata.domain.PickDetail;
import com.youchain.businessdata.domain.PickTicket;
import com.youchain.businessdata.domain.PlanPickDetail;
import com.youchain.businessdata.repository.InventoryBakRepository;
import com.youchain.businessdata.service.InventoryBakService;
import com.youchain.businessdata.service.PickDetailService;
import com.youchain.businessdata.service.PickTicketService;
import com.youchain.exception.BadRequestException;
import com.youchain.utils.*;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.PlanPickDetailRepository;
import com.youchain.businessdata.service.PlanPickDetailService;
import com.youchain.businessdata.service.dto.PlanPickDetailDto;
import com.youchain.businessdata.service.dto.PlanPickDetailQueryCriteria;
import com.youchain.businessdata.service.mapstruct.PlanPickDetailMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
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.sql.Timestamp;
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 jiangkun
* @date 2024-01-23
**/
@Service
@RequiredArgsConstructor
@Slf4j
public class PlanPickDetailServiceImpl implements PlanPickDetailService {

    private final PlanPickDetailRepository planPickDetailRepository;
    private final PlanPickDetailMapper planPickDetailMapper;
    private final EntityManager entityMapper;
    private final BomAccountService bomAccountService;
    private final PickTicketService pickTicketService;
    private final PickDetailService pickDetailService;
    private final AreaService areaService;
    private final AreaRepository areaRepository;
    private final InventoryBakService inventoryBakService;
    private final BomAccountRepository bomAccountRepository;
    private final AutomaticPlanDetailRepository automaticPlanDetailRepository;
    private final InventoryBakRepository inventoryBakRepository;

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

    @Override
    public List<PlanPickDetailDto> queryAll(PlanPickDetailQueryCriteria criteria){
        return planPickDetailMapper.toDto(planPickDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public PlanPickDetailDto findById(Long id) {
        PlanPickDetail planPickDetail = planPickDetailRepository.findById(id).orElseGet(PlanPickDetail::new);
        ValidationUtil.isNull(planPickDetail.getId(),"PlanPickDetail","id",id);
        return planPickDetailMapper.toDto(planPickDetail);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PlanPickDetailDto create(PlanPickDetail resources) {
        return planPickDetailMapper.toDto(planPickDetailRepository.save(resources));
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            PlanPickDetailDto byId = this.findById(id);
            if (byId.getStatus().equals(BizStatus.YCD)){
                throw new BadRequestException(HttpStatus.NOT_FOUND,"单号为:"+byId.getCode()+"的机型为:"+byId.getBigItem().getCode()+"已出单");
            }
            planPickDetailRepository.deleteById(id);
        }
    }

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

    public List<PlanPickDetail> queryPlanPickDetail(String code) {
        String hql = "from PlanPickDetail t where t.code= '" + code + "'";
        Query query = entityMapper.createQuery(hql);
        List<PlanPickDetail> resultList = query.getResultList();
        return  resultList;
    }

    @Override
    public List queryGwList(String code, String gw){
        String hql  = "select ptd.zone.code from PlanPickDetail  ptd " +
                    " where ptd.code='"+code+"' and  ptd.zone.code!='"+gw+"'";
        Query query = entityMapper.createQuery(hql);
        List<Object[]> resultList = query.getResultList();
        return  resultList;
    }

    @Override
    public List queryStatusList(String code){
        String hql  = "select ptd.zone.code from PlanPickDetail  ptd " +
                " where ptd.code='"+code+"' and  ptd.status!='"+BizStatus.WCD+"'";
        Query query = entityMapper.createQuery(hql);
        List<Object[]> resultList = query.getResultList();
        return  resultList;
    }

    public void createAutoPlan(int pcNum, String code, Long shAreaId, AutomaticPlanDetail detail, Boolean isLast, Timestamp batchTime){
        //生成备货操作
        List<PlanPickDetail> planPickDetails = planPickDetailRepository.findByStatusAndCode("WCD",code);
        for (PlanPickDetail ppd : planPickDetails) {
            List<BomAccount> bs = bomAccountService.queryBomAccount(ppd.getBigItem().getId(), shAreaId,ppd.getZone().getWorkingStation());
            if (bs.size() <= 0) {
                throw new BadRequestException(detail.getShArea().getWorkingStation()+"工位"+ppd.getBigItem().getCode() + "未查到对应BOM工位清单");
            }
            ppd.setPxDetailId(detail.getId());
            ppd.setIsLast(isLast);
            ppd.setAllocatedQuantity(ppd.getOrderQuantity());
            ppd.setStatus(BizStatus.YCD);
            this.update(ppd);
        }
        PlanPickDetail ppd_o=planPickDetails.get(0);
        //得到所有的物料和明细
        List<Object[]> objPicks = bomAccountService.queryBomAccountList(code,null, shAreaId, null,"0");
        for (Object[] objPick : objPicks) {
            Long oAreaId = (Long) objPick[0];
            String bpType = (String) objPick[1];
            Area oArea=areaService.findEntityById(oAreaId);
            PickTicket pickTicket = pickTicketService.storePick(ppd_o.getBillType(), ppd_o.getZone(),oArea, bpType, ppd_o.getCode());
            pickTicket.setGcCode(ppd_o.getZone().getGcCode());
            pickTicket.setOrderDate(new Timestamp(detail.getJhDate().getTime()));
            double orderQty = 0;
            List<Object[]> objs = bomAccountService.queryBomAccountList(ppd_o.getCode(), oAreaId,ppd_o.getZone().getId(), bpType, "1");
            //需求数量
            double xqty = 0d;
            //纯需求数量
            double cxqty = 0d;
            for (Object[] obj : objs) {
                Long bId = (Long) obj[0];
                double xqQty = (Double) obj[1];
                BomAccount ba = bomAccountService.findByEntity(bId);
                PickDetail ptd = new PickDetail();
                //需求数xq_qty=数量*单用
                ptd.setXqQty(xqQty);
                ptd.setBomId(ba.getId());
                Double xbQty=inventoryBakService.getXbQty(ba.getItem().getId(),pickTicket.getShArea().getId(),ba.getZPoint().getId(),detail.getId());
                if(xbQty<=0){
                    xbQty=0d;
                }
                ptd.setXbQty(xbQty);
                //获取批次需求数，因同一工位品番有多个数量，需汇总统计
                double pc_qty=bomAccountRepository.getPcQty(ba.getRArea().getId(),ba.getItem().getId(),ba.getZPoint().getId());
                //批次需求数,存入BOM中
                ptd.setPureReqQty(pc_qty);
                //纯需求数 【BOM单用*（铺线计划台数10台+第一批的10台+第二批的10台）-第一批需求-线边库存】/收容数*收容数
                ptd.setPropC4(xqQty-ptd.getPureReqQty()-ptd.getXbQty());
                if(ptd.getPropC4().intValue()<=0){
                    ptd.setPropC4(0d);
                }else{
                    //备货需求=（纯需求数/收容数向上取整）*收容数
                    ptd.setOrderQty(Math.ceil(ptd.getPropC4()/ba.getItem().getExtendD3())*ba.getItem().getExtendD3());
                }
                ba.setPcQty(ptd.getOrderQty()+ba.getPcQty());
                bomAccountService.update(ba);
                xqty += ptd.getXqQty();
                cxqty += ptd.getPropC4();
                ptd.setPoint(ba.getZPoint());
                ptd.setItem(ba.getItem());
                ptd.setPickTicket(pickTicket);
                ptd.setContents(ba.getContents());
                ptd.setAc(ba.getAc());
                ptd.setSupplier(ba.getSupplier());
                ptd.setArea(pickTicket.getArea());
                ptd.setShArea(pickTicket.getShArea());
                pickDetailService.create(ptd);
                orderQty += ptd.getOrderQty();
                //查询组合物料，数量是否一致，不一致改成一致
                String largeClass=ba.getItem().getLargeClass();
                if(largeClass!=null&&!largeClass.equals("")){
                    int maxQty=pickDetailService.getMaxBomQty(pickTicket.getId(),largeClass).intValue();
                    if(maxQty>0) {
                        List<PickDetail> ptds = pickDetailService.getBomList(pickTicket.getId(), largeClass);
                        for (PickDetail d : ptds) {
                            if (d.getOrderQty().intValue() != maxQty) {
                                orderQty -= d.getOrderQty();
                                d.setRemark("原" + d.getOrderQty() + "调整到" + maxQty);
                                d.setOrderQty(maxQty + 0d);
                                pickDetailService.update(d);
                                orderQty += d.getOrderQty();
                            }
                        }
                    }
                }
            }
            pickTicket.setOrderQuantity(orderQty);
            pickTicket.setBhQty(orderQty);
            //纯需求数
            pickTicket.setPureReqQty(cxqty);
            //需求数量
            pickTicket.setXqQty(xqty);
            pickTicket.setPc("第"+pcNum+"批");
            pickTicket.setBatchTime(batchTime);
            pickTicketService.update(pickTicket);
        }
    }
    public void createAutoPlan(String[] codes,Long[] detailIds,String type) {
        List<PlanPickDetail> planPickDetails = planPickDetailRepository.findByStatusAndCodes("WCD",codes);
        for (PlanPickDetail ppd : planPickDetails) {
            List<BomAccount> bs = bomAccountService.queryBomAccount(ppd.getBigItem().getId(), ppd.getZone().getId(),ppd.getZone().getWorkingStation());
            if (bs.size() <= 0) {
                throw new BadRequestException(ppd.getZone().getWorkingStation()+"工位"+ppd.getBigItem().getCode() + "未查到对应BOM工位清单");
            }
            ppd.setAllocatedQuantity(ppd.getOrderQuantity());
            ppd.setStatus(BizStatus.YCD);
            this.update(ppd);
        }
        PlanPickDetail ppd_o=planPickDetails.get(0);
        Timestamp orderDate=new Timestamp(new Date().getTime());
        if(ppd_o.getPxDetailId()!=null) {
            AutomaticPlanDetail detail =automaticPlanDetailRepository.getById(ppd_o.getPxDetailId());
            orderDate=new Timestamp(detail.getJhDate().getTime());
        }
        //按照所属工厂+批次查找对应数据
        List<Object[]> gcpcs = planPickDetailRepository.groupGcPc(codes);
        for (Object[] gcpc : gcpcs) {
            String gc=gcpc[0].toString();
            String pc=gcpc[1].toString();
            Long ppdId=Long.parseLong(gcpc[2].toString());
            PlanPickDetail ppd=planPickDetailRepository.getById(ppdId);
            //查找出库库区是否有多个
            List<Long> cAreaIds = planPickDetailRepository.groupCArea(codes,gc,pc);
            for (Long cAreaId : cAreaIds) {
                Area oArea=areaService.findEntityById(cAreaId);
                PickTicket pickTicket = pickTicketService.storePick(ppd_o.getBillType(), null,oArea, "大", Arrays.toString(codes));
                pickTicket.setGcCode(gc);
                pickTicket.setOrderDate(orderDate);
                double orderQty = 0;
                List<Object[]> objs = planPickDetailRepository.sumBomSingle(codes,gc,pc,cAreaId);
                //需求数量
                double xqty = 0d;
                //纯需求数量
                double cxqty = 0d;
                for (Object[] obj : objs) {
                    Long rAreaId = (Long) obj[1];
                    Long bId = (Long) obj[1];
                    double xqQty = (Double) obj[2];
                    BomAccount ba = bomAccountService.findByEntity(bId);
                    PickDetail ptd = new PickDetail();
                    //需求数xq_qty=数量*单用
                    ptd.setXqQty(xqQty);
                    ptd.setBomId(ba.getId());
                    if(detailIds!=null) {//自动叫料逻辑
                        Double xbQty = inventoryBakRepository.getXbQty(ba.getItem().getId(), ba.getRArea().getId(), detailIds, ba.getZPoint().getId());
                        if (xbQty == null || xbQty <= 0) {
                            xbQty = 0d;
                        }
                        ptd.setXbQty(xbQty);
                        Double xbBhQty=0d;
                        if(type!=null&&type.equals(BizStatus.PX_BH)){
                            xbBhQty= inventoryBakRepository.getXbBhQty(ba.getItem().getId(), ba.getRArea().getId(), detailIds, ba.getZPoint().getId());
                            if (xbBhQty == null || xbBhQty <= 0) {
                                xbBhQty = 0d;
                            }
                        }
                        ptd.setXbBhQty(xbBhQty);

                        //获取批次需求数，因同一工位品番有多个数量，需汇总统计
                        double pc_qty = bomAccountRepository.getPcQty(ba.getRArea().getId(), ba.getItem().getId(), ba.getZPoint().getId());
                        //批次需求数,存入BOM中
                        ptd.setPureReqQty(pc_qty);
                    }
                    //纯需求数 【BOM单用*（铺线计划台数10台+第一批的10台+第二批的10台）-第一批需求-线边库存】/收容数*收容数
                    ptd.setPropC4(xqQty-ptd.getPureReqQty()-ptd.getXbQty()-ptd.getXbBhQty());
                    if(ptd.getPropC4().intValue()<=0){
                        ptd.setPropC4(0d);
                    }else{
                        //备货需求=（纯需求数/收容数向上取整）*收容数
                        ptd.setOrderQty(Math.ceil(ptd.getPropC4()/ba.getItem().getExtendD3())*ba.getItem().getExtendD3());
                    }
                    ba.setPcQty(ptd.getOrderQty()+ba.getPcQty());
                    bomAccountService.update(ba);
                    xqty += ptd.getXqQty();
                    cxqty += ptd.getPropC4();
                    ptd.setPoint(ba.getZPoint());
                    ptd.setItem(ba.getItem());
                    ptd.setPickTicket(pickTicket);
                    ptd.setContents(ba.getContents());
                    ptd.setAc(ba.getAc());
                    ptd.setSupplier(ba.getSupplier());
                    ptd.setArea(pickTicket.getArea());
                    ptd.setShArea(ba.getRArea());
                    pickDetailService.create(ptd);
                    orderQty += ptd.getOrderQty();
                    //查询组合物料，数量是否一致，不一致改成一致
                    String largeClass=ba.getItem().getLargeClass();
                    if(largeClass!=null&&!largeClass.equals("")){
                        int maxQty=pickDetailService.getMaxBomQty(pickTicket.getId(),largeClass).intValue();
                        if(maxQty>0) {
                            List<PickDetail> ptds = pickDetailService.getBomList(pickTicket.getId(), largeClass);
                            for (PickDetail d : ptds) {
                                if (d.getOrderQty().intValue() != maxQty) {
                                    orderQty -= d.getOrderQty();
                                    d.setRemark("原" + d.getOrderQty() + "调整到" + maxQty);
                                    d.setOrderQty(maxQty + 0d);
                                    pickDetailService.update(d);
                                    orderQty += d.getOrderQty();
                                }
                            }
                        }
                    }
                }
                pickTicket.setOrderQuantity(orderQty);
                pickTicket.setBhQty(orderQty);
                //纯需求数
                pickTicket.setPureReqQty(cxqty);
                //需求数量
                pickTicket.setXqQty(xqty);
                pickTicket.setPc(pc);
                pickTicket.setBatchTime(ppd.getBatchTime());
                pickTicketService.update(pickTicket);
            }
        }
    }
}