/*
 *  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.Item;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.basicdata.repository.PointRepository;
import com.youchain.basicdata.repository.StockRepository;
import com.youchain.basicdata.service.StockService;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.inputJson.Zhengli;
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 java.util.List;
import java.util.Map;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.LinkedHashMap;

/**
 * @author hjl
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-08-14
 **/
@Service
@RequiredArgsConstructor
public class AsnDetailServiceImpl implements AsnDetailService {

    private final AsnDetailRepository asnDetailRepository;
    private final TaskRepository taskRepository;
    private final XppRecordRepository xppRecordRepository;
    private final StockRepository stockRepository;
    private final PointRepository pointRepository;
    private final AsnDetailMapper asnDetailMapper;
    private final EntityManager entityMapper;
    private final AsnService asnService;
    private final AsnMapper asnMapper;
    private final InventoryService inventoryService;
    private final InventoryLogService inventoryLogService;
    private final ItemKeyService itemKeyService;
    private final TaskService taskService;

    @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();
            }
            Inventory inventory = inventoryService.getInventory(t.getItemKey(), t.getArea(), srcPoint, t.getAsnDetail().getPoint(), t.getArea().getDept(), BizStatus.RECEIVING_CANCEL);
            if (inventory == null) {
                throw new BadRequestException("找不到对应库存");
            }
            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, null, 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 (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.getSpecQuantity());
        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
    @Transactional(rollbackFor = Exception.class)
    public void zhengli(Zhengli zhengli) {
        AsnDetail asnDetail = asnDetailRepository.findById(zhengli.getId()).get();
        Item item = asnDetail.getItem();
        Stock stock = zhengli.getStock();
        Point point = zhengli.getPoint();
        Area area = zhengli.getArea();
        if (item.getIsInspection()) {
            throw new BadRequestException("该商品需要质检，请先完成质检！");
        }
        if(stock==null){
            throw new BadRequestException("整理的容器不能为空！");
        }

        //生成Itemkey
        ItemKey itemKey = itemKeyService.getItemKey(item, asnDetail.getPropC1(), asnDetail.getPropC3(), asnDetail.getPropC4(), asnDetail.getPropC5(), asnDetail.getPropC6(), asnDetail.getPropD1());

        //生成库存记录
        Inventory inventory = inventoryService.getInventory(itemKey, point, stock, item.getDept(), BizStatus.ASN,area);
        inventory.setStatus("待入库");
        inventory.setQuantity(inventory.getQuantity() + zhengli.getZlQty());
        inventoryService.update(inventory);

        //生成入库记录
        Task task = taskService.storeTask(asnDetail, null, zhengli.getArea(), itemKey, null, point, zhengli.getZlQty());
        task.setSrcStockCode(stock.getCode());
        task.setSrcStock(stock);
        task.setInvId(inventory.getId());
        taskRepository.save(task);



        //是序列号的商品，生成序列号记录
        if (item.getIsSerial()) {
            XppRecord xppRecord = new XppRecord();
            xppRecord.setRkTask(task);
            xppRecord.setItemKey(itemKey);
            xppRecord.setInvPoint(asnDetail.getPoint());
            xppRecordRepository.save(xppRecord);
        }

        //回写收货数量
        asnDetail.setStock(zhengli.getStock());
        asnDetail.setPoint(zhengli.getPoint());
        asnDetail.setReceivedQty(asnDetail.getReceivedQty() + zhengli.getZlQty());
        asnDetailRepository.save(asnDetail);

        //容器绑定
        stock.setStatus(BaseStatus.USED);
        stock.setDept(item.getDept());
        stockRepository.save(stock);

        if (point != null) {
            point.setStatus(BaseStatus.USED);
            pointRepository.save(point);
        }


        //刷新单头状态
        updateAsnStatus(asnDetail.getAsn());
    }

    @Override
    public void updateAsnStatus(Asn asn) {
        double orderQty = 0;
        double receivedQty = 0;
        List<AsnDetail> asnDetails = asnDetailRepository.queryByAsnId(asn.getId());
        for (AsnDetail detail : asnDetails) {
            orderQty += detail.getOrderQty();
            receivedQty += detail.getReceivedQty();
        }
        asn.setOrderQuantity(orderQty);
        asn.setReceivedQuantity(receivedQty);
        if (orderQty == receivedQty) {
            asn.setStatus(BizStatus.RECEIVED);
        } else if (receivedQty > 0 && receivedQty < orderQty) {
            asn.setStatus(BizStatus.RECEIVING);
        } else if (receivedQty == 0) {
            asn.setStatus(BizStatus.OPEN);
        }
        asnService.update(asn);
    }
}
