/*
*  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.*;
import com.youchain.basicdata.repository.PointRepository;
import com.youchain.basicdata.service.AreaService;
import com.youchain.basicdata.service.PointService;
import com.youchain.basicdata.service.StockService;
import com.youchain.basicdata.service.dto.AreaDto;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.repository.InventoryRepository;
import com.youchain.businessdata.repository.TaskRepository;
import com.youchain.businessdata.repository.XppRecordRepository;
import com.youchain.businessdata.service.*;
import com.youchain.businessdata.service.dto.AsnDto;
import com.youchain.businessdata.service.mapstruct.AsnMapper;
import com.youchain.exception.BadRequestException;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.AsnDetailRepository;
import com.youchain.businessdata.service.dto.AsnDetailDto;
import com.youchain.businessdata.service.dto.AsnDetailQueryCriteria;
import com.youchain.businessdata.service.mapstruct.AsnDetailMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.RequestBody;

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 hjl
* @date 2023-08-14
**/
@Service
@RequiredArgsConstructor
public class AsnDetailServiceImpl implements AsnDetailService {

    private final AsnDetailRepository asnDetailRepository;
    private final PointRepository pointRepository;
    private final XppRecordRepository xppRecordRepository;
    private final InventoryRepository inventoryRepository;
    private final AsnDetailMapper asnDetailMapper;
    private final EntityManager entityMapper;
    private final TaskRepository taskRepository;

    private final AsnService asnService;
    private final XppRecordService xppRecordService;
    private final InventoryService inventoryService;
    private final InventoryLogService inventoryLogService;
    private final PointService pointService;
    private final AreaService areaService;
    private final ItemKeyService itemKeyService;
    private final TaskService taskService;

    private final AsnMapper asnMapper;

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

    @Override
    public List<AsnDetailDto> queryAll(AsnDetailQueryCriteria criteria){
        return asnDetailMapper.toDto(asnDetailRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root,criteria,criteriaBuilder)));
    }

    @Override
    @Transactional
    public AsnDetailDto findById(Long id) {
        AsnDetail asnDetail = asnDetailRepository.findById(id).orElseGet(AsnDetail::new);
        ValidationUtil.isNull(asnDetail.getId(),"AsnDetail","id",id);
        return asnDetailMapper.toDto(asnDetail);
    }

    @Override
    @Transactional
    public AsnDetail getEntity(Long id) {
        AsnDetail asnDetail = asnDetailRepository.findById(id).orElseGet(AsnDetail::new);
        return asnDetail;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AsnDetailDto create(AsnDetail resources) {
        return asnDetailMapper.toDto(asnDetailRepository.save(resources));
    }

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

    @Override
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            AsnDetail asnDetail = asnDetailRepository.getById(id);
            if (asnDetail.getStatus().equals("OPEN")){
                //修改容器状态
                //删除关联表的数据 入库单明细(data_asn_detail)
                if (taskRepository.getAsnDetailIdToId(id)!=null){
                    taskRepository.deleteById(taskRepository.getAsnDetailIdToId(id));
                }
                //扣入库表的订单数量
                Double orderQty = asnDetail.getOrderQty();
                AsnDto byId = asnService.findById(asnDetail.getAsn().getId());
                byId.setOrderQuantity(byId.getOrderQuantity()-orderQty);
                asnService.update(asnMapper.toEntity(byId));
            }
            asnDetailRepository.deleteById(id);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelPut(Long taskId, XppRecord xppRecord) {
        Task t=taskRepository.getById(taskId);
        AsnDetail d=t.getAsnDetail();
        Asn asn=d.getAsn();
        String ewm=null;
        if(t.getPlanQty()>0){
            Point srcPoint=t.getDstPoint();
            if(xppRecord!=null){
                ewm=xppRecord.getEwm();
                srcPoint=xppRecord.getInvPoint();
            }
            String xdh=null;
            if(asn!=null){
                xdh=asn.getCusCode();
            }
            Inventory inventory=inventoryService.getInventory(t.getItemKey(),srcPoint.getArea(),srcPoint,t.getAsnDetail().getPoint(),t.getArea().getDept(),BizStatus.RECEIVING_CANCEL,xdh);
            if(inventory==null){
                throw new BadRequestException("找不到对应库存");
            }
            if(!inventory.getArea().getBexb()) {
                if ((inventory.getQuantity().intValue() - inventory.getQueuedQty().intValue()) < t.getPlanQty().intValue()) {
                    throw new BadRequestException("库存不足");
                }
            }
            double srcQty= inventory.getQuantity();
            inventory.setQuantity(inventory.getQuantity()-t.getPlanQty());
            inventoryService.update(inventory);
            d.setReceivedQty(d.getReceivedQty()-t.getPlanQty());
            if(asn!=null){
                asn.setReceivedQuantity(asn.getReceivedQuantity()-t.getPlanQty());
            }

            InventoryLog log=inventoryLogService.storeInventoryLog(BizStatus.RECEIVING_CANCEL,BizStatus.REDUCE,t.getBillCode(),t.getArea(),t.getItemKey(),t.getDstPoint(),t.getSrcPoint(),null,null,srcQty,t.getPlanQty(),
                    null,ewm, BizStatus.ASN,inventory.getId(),inventory.getId(),"取消上架");
            taskRepository.delete(t);
            if(xppRecord!=null&&d!=null){
                this.delete(d.getId());
            }
        }
    }


    public void delete(Long id) {
        asnDetailRepository.deleteById(id);
    }

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

    @Override
    public  AsnDetail toEntity(AsnDetailDto detailDto) {
        return asnDetailMapper.toEntity(detailDto);
    }
    @Override
    public AsnDetail findByStock(String code){
        String hql="select d from AsnDetail d where d.stock.code='"+code+"' and d.status='"+ BizStatus.OPEN+"'";
        Query query=entityMapper.createQuery(hql);
        List<AsnDetail> ts=query.getResultList();
        if(ts.size()>0){
            return ts.get(0);
        }
        return  null;
    }


    @Override
    public AsnDetail createAsnDetail(Item item, Stock stock, Point srcPoint,String propC1,String gdh){
        AsnDetail asnDetail = new AsnDetail();
        asnDetail.setItem(item);
        asnDetail.setLineNo(1l);
        asnDetail.setStatus(BizStatus.OPEN);
        asnDetail.setOrderQty(item.getExtendD1());
        asnDetail.setDept(item.getDept());
        asnDetail.setStock(stock);
        asnDetail.setPoint(srcPoint);
        asnDetail.setPropC1(propC1);
        asnDetail.setOrderNumber(gdh);
        return  asnDetail;
    }

    @Override
    public List<AsnDetail> findAsnDetails(Long asnId,String type) {
        String hql =" from AsnDetail ad where ad.asn.id="+asnId;
        if(type.equals("1")){//整单收货,查询未收货数据
             hql+=" and ad.receivedQty<orderQty";
        }
        Query query=entityMapper.createQuery(hql);
        List<AsnDetail> ds=query.getResultList();
        return ds;
    }

    @Override
    public void putAwayDetial(Long asnDetailId, Long pointId) {
       AsnDetail ad=asnDetailRepository.getById(asnDetailId);
       Point point=pointRepository.getById(pointId);

    }
    @Override
    public void putawayInv(@RequestBody Long asnDetailId, Long areaId, Long pointId, double recQty, String ewm) {
        AsnDetail d = asnDetailRepository.getById(asnDetailId);
        String propC2=d.getPropC2();
        if(d.getPropC2()!=null){
            if(d.getPropC2().indexOf("EXP")>=0){
                propC2=BaseStatus.BS;
            }else if(d.getPropC2().indexOf("DOM")>=0){
                propC2=BaseStatus.KS;
            }
        }
        if(propC2==null||propC2.equals("")){
            propC2=BaseStatus.KS;
        }
        Area area =null;
        Point point = null;
        String gdItemCode=null;
        if(pointId!=null){
            point = pointService.findEntityById(pointId);
            if( point.getType().equals(BaseStatus.CH)){
                area=point.getArea();
            }
            gdItemCode=point.getItemCode();
        }
        if(gdItemCode!=null&&!gdItemCode.equals("")&&!d.getItem().getCode().equals(gdItemCode)){
            throw new BadRequestException("品番"+d.getItem().getCode()+"和库位"+point.getCode()+"固定品番"+gdItemCode+"不匹配");
        }
        if(areaId!=null){
            area = areaService.findEntityById(areaId);
        }
        Point zzkw=null;
        String pc1=null;
//        if(area.getBexb()){
//            point= pointService.getPoint(area.getPointCode(), null, BaseStatus.HCKW, null);//取默认线边库位
//            zzkw=d.getPoint();
//            if(zzkw==null){
//                //取默认制造库位
//                zzkw= pointService.getPoint(BaseStatus.ZZKW, null, null,  null);
//            }
//        }else{
//            pc1=DateUtil.dateYmdz();
//        }
//        if(!area.getBexb()){
//            pc1=DateUtil.dateYmdz();
//        }
        if(point==null){
            throw new BadRequestException("请选择入库库位");
        }
        if(point.getType().equals(BaseStatus.CH)){//材管库位入库需要批次
            pc1=DateUtil.dateYmdz();
        }
        double unRecQty=d.getOrderQty() - d.getReceivedQty();
        if ( recQty<=unRecQty) {
            //现品票确认将任务id回写到现品票表中
            XppRecord xppRecord = xppRecordRepository.findByEwmType(ewm,BillParmType.XPP_1001);
            ItemKey ik=null;
            if(xppRecord!=null){
                if(!xppRecord.getStatus().equals(BizStatus.RECEIVED)&&!xppRecord.getStatus().equals(BizStatus.RETENTION_IN)){
                    throw new BadRequestException(d.getItem().getCode()+"现品票状态不正确");
                }
                ik=xppRecord.getItemKey();
            }
            if(ik==null){
                ik = itemKeyService.getItemKey(d.getItem(), pc1,propC2);
            }
            String billCode=null;
            String stockCode=null;
            if(d.getAsn()!=null){
                Asn asn=d.getAsn();
                billCode=asn.getCode();
                asn.setReceivedQuantity(asn.getReceivedQuantity()+recQty);
                if(asn.getReceivedQuantity().intValue()>=asn.getOrderQuantity().intValue()) {
                    asn.setStatus(BizStatus.PUTAWAY);
                    asn.setReceivedDate(new Timestamp(new Date().getTime()));
                    asn.setArea(point.getArea());
                    asn.setRelatedBill3(point.getCode());
                }
                asnService.update(asn);
                stockCode=asn.getCusCode();
            }
            Task t = taskService.storeTask(d, null, area, ik, point, point,recQty,stockCode);
            if(xppRecord!=null) {
                xppRecord.setRkTask(t);
                xppRecord.setInvPoint(point);
                xppRecord.setStatus(BizStatus.PUTAWAY);
                xppRecord.setItemKey(ik);
                xppRecord.setSjr(SecurityUtils.getCurrentUsername());
                xppRecord.setSjDate(new Timestamp(new Date().getTime()));
                ewm=xppRecord.getEwm();
                xppRecordService.update(xppRecord);
            }
            d.setReceivedQty(d.getReceivedQty()+recQty);
            if(d.getReceivedQty().intValue()>=d.getOrderQty().intValue()){
                d.setStatus(BizStatus.PUTAWAY);
            }else if(d.getReceivedQty().intValue()>0){
                d.setStatus(BizStatus.PUTAWAY);
            }
            this.update(d);
            point.setStatus(BaseStatus.USED);
            pointService.update(point);
            Inventory inv = inventoryService.getInventory(ik, area, point, zzkw, d.getDept(), BizStatus.RECEIVING_UP,stockCode);
            t.setInvId(inv.getId());
            taskService.update(t);
            double srcQty = inv.getQuantity();
            inv.addQty(recQty);

            inventoryService.update(inv);
            Point srcPoint = pointService.getPoint(null, null, BaseStatus.SHZC, null);
            InventoryLog log=inventoryLogService.storeInventoryLog(BizStatus.RECEIVING_UP, BizStatus.ADD, billCode, area, ik, srcPoint, point, zzkw, srcQty, recQty,ewm,
                    BizStatus.ASN, d.getId(), inv.getId(), d.getRemark());
            log.setDstStockCode(inv.getStockCode());
            inventoryLogService.update(log);
        } else {
            throw new BadRequestException(d.getItem().getCode() + "收货数量不能大于未收数量");
        }
    }

}
