/*
 *  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.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.inputJson.IScanPut;
import com.youchain.businessdata.inputJson.buttenJson.PickOutButton;
import com.youchain.businessdata.repository.InventoryRepository;
import com.youchain.businessdata.repository.PickTicketRepository;
import com.youchain.businessdata.repository.TaskLogRepository;
import com.youchain.businessdata.returnJson.RPPickList;
import com.youchain.businessdata.service.*;
import com.youchain.exception.BadRequestException;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.PickOutRepository;
import com.youchain.businessdata.service.dto.PickOutDto;
import com.youchain.businessdata.service.dto.PickOutQueryCriteria;
import com.youchain.businessdata.service.mapstruct.PickOutMapper;
import org.hibernate.SQLQuery;
import org.hibernate.transform.AliasToEntityMapResultTransformer;
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;

/**
 * @author jiangkun
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2024-02-21
 **/
@Service
@RequiredArgsConstructor
public class PickOutServiceImpl implements PickOutService {

    private final PickOutRepository pickOutRepository;
    private final PickOutMapper pickOutMapper;
    private final TaskLogRepository taskLogRepository;
    //生成单号工具
    private final CodeUtils codeUtils;
    private final TaskLogService taskLogService;
    private final PickDetailService pickDetailService;
    //    private final PickTicketService pickTicketService;
    private final PickTicketRepository pickTicketRepository;
    private final InventoryLogService inventoryLogService;
    private final InventoryService inventoryService;
    private final InventoryRepository inventoryRepository;
    private final EntityManager entityManager;

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

    @Override
    public List<PickOutDto> queryAll(PickOutQueryCriteria criteria) {
        return pickOutMapper.toDto(pickOutRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public PickOutDto findById(Long id) {
        PickOut pickOut = pickOutRepository.findById(id).orElseGet(PickOut::new);
        ValidationUtil.isNull(pickOut.getId(), "PickOut", "id", id);
        return pickOutMapper.toDto(pickOut);
    }

    @Override
    @Transactional
    public PickOut findByEntity(Long id) {
        PickOut pickOut = pickOutRepository.findById(id).orElseGet(PickOut::new);
        return pickOut;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PickOutDto create(PickOut resources) {
        return pickOutMapper.toDto(pickOutRepository.save(resources));
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(Long[] ids) {
        for (Long id : ids) {
            taskLogRepository.delectTaskLogPickOutId(id);
            pickOutRepository.deleteById(id);
        }
    }

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

    @Override
    public List<TaskLog> getTaskLogNotPickOut(PickOutButton pickOutButton) {
        String hql = "";
        if (pickOutButton.getPickOutId() != null) {
            hql = " from TaskLog tl where tl.pickOut.id = " + pickOutButton.getPickOutId();
        } else {
            hql = " from TaskLog tl where tl.pickOut = NULL and tl.task.pickDetail.pickTicket != null ";
        }
        if (pickOutButton.getItemCode() != null && !pickOutButton.getItemCode().isEmpty()) {
            hql = hql + " and tl.item.code = '" + pickOutButton.getItemCode() + "'";
        }
        if (pickOutButton.getSrcPointCode() != null && !pickOutButton.getSrcPointCode().isEmpty()) {
            hql = hql + " and tl.srcPoint.code = '" + pickOutButton.getSrcPointCode() + "'";
        }
        if (pickOutButton.getDstStockCode() != null && !pickOutButton.getDstStockCode().isEmpty()) {
            hql = hql + " and tl.dstStockCode = '" + pickOutButton.getDstStockCode() + "'";
        }
        Query query = entityManager.createQuery(hql);
        List<TaskLog> taskLogs = query.getResultList();
        return taskLogs;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PickOut createPickOut(PickOutButton pickOutButton) {
        //新政填写的数据
        PickOut pickOut = pickOutButton.getPickOut();
        pickOut.setOrderNo(codeUtils.getCode_yyMMdd("CK", 3));
        return pickOutRepository.save(pickOut);
    }

    @Override
    public void addData(PickOutButton pickOutButton) {
        //向那张表添加数据
        PickOut pickOut = pickOutRepository.getById(pickOutButton.getPickOutId());
        //选择的tasklog要绑定pickOut的数据
        Long[] taskLogIdS = pickOutButton.getTaskLogIdS();
        //添加成功，订单数量对应累计
        double orderQuantity = 0d;
        if (taskLogIdS.length > 0) {
            for (Long taskLogId : taskLogIdS) {
                TaskLog taskLog = taskLogRepository.getById(taskLogId);
                taskLog.setPickOut(pickOut);
                taskLogService.update(taskLog);
                orderQuantity += taskLog.getMoveQty();
            }
        }
        pickOut.setOrderQty(pickOut.getOrderQty() + orderQuantity);
        this.update(pickOut);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PickOut createPickOutDto(PickOutButton pickOutButton) {
        //新政填写的数据
        String ck = codeUtils.getCode_yyMMdd("CK", 3);
        PickOut pickOut = new PickOut();
        pickOut.setOrderNo(ck);
        //新保存
        PickOut save = pickOutRepository.save(pickOut);
        //添加成功，订单数量对应累计
        double orderQuantity = 0d;
        //选择的tasklog要绑定pickOut的数据
        Long[] taskLogIdS = pickOutButton.getTaskLogIdS();
        //容器码
        String stockCode = taskLogRepository.getById(taskLogIdS[0]).getDstStockCode();
        if (taskLogIdS.length > 0) {
            for (Long taskLogId : taskLogIdS) {
                if (stockCode != null) {
                    TaskLog taskLog = taskLogRepository.getById(taskLogId);
                    if (stockCode.equals(taskLog.getDstStockCode())) {
                        taskLog.setPickOut(save);
                        taskLogRepository.save(taskLog);
                        orderQuantity += taskLog.getMoveQty();
                    } else {
                        throw new BadRequestException(HttpStatus.NOT_FOUND, "容器码不一致");
                    }
                } else {
                    TaskLog taskLog = taskLogRepository.getById(taskLogId);
                    if (!Objects.isNull(taskLog.getDstStockCode())) {
                        throw new BadRequestException(HttpStatus.NOT_FOUND, "容器码不一致");
                    }
                    taskLog.setPickOut(save);
                    taskLogRepository.save(taskLog);
                    orderQuantity += taskLog.getMoveQty();
                }
            }
        }
        save.setOrderQty(orderQuantity);
        this.update(save);
        return save;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmPickOut(PickOutButton pickOutButton) {
        Long[] pickOutIdS = pickOutButton.getPickOutIdS();
        for (Long pickOutId : pickOutIdS) {
            PickOut pickOut = pickOutRepository.getById(pickOutId);
            if (pickOut.getStatus().equals(BizStatus.SHIP_ALL)) {
                throw new BadRequestException(HttpStatus.NOT_FOUND, pickOut.getOrderNo() + "该单已全部发运");
            }
            List<TaskLog> taskLogs = taskLogRepository.getTaskLogByPickOutId(pickOutId);
            if (!taskLogs.isEmpty()) {
                //判断是不是部分出库
                Long[] taskLogIdS = pickOutButton.getTaskLogIdS();
                if (taskLogIdS.length > 0) {
                    List<TaskLog> taskLogList = new ArrayList<>();
                    for (Long taskLogId : taskLogIdS) {
                        TaskLog taskLog = taskLogRepository.getById(taskLogId);
                        taskLog.setPickOut(pickOut);
                        taskLogList.add(taskLog);
                    }
                    taskLogs = taskLogList;
                }
                for (TaskLog taskLog : taskLogs) {
                    if ((taskLog.getMoveQty() - taskLog.getShipQty()) == 0d) {
                        continue;
                    }
                    //出库明细
                    PickDetail pickDetail = taskLog.getTask().getPickDetail();
                    if (Objects.isNull(pickDetail)) {
                        throw new BadRequestException(HttpStatus.NOT_FOUND, taskLog.getItem().getCode() + "未发现明细数据" + taskLog.getId());
                    }
                    //出库主表
                    PickTicket pickTicket = taskLog.getTask().getPickDetail().getPickTicket();
                    if (Objects.isNull(pickTicket)) {
                        throw new BadRequestException(HttpStatus.NOT_FOUND, taskLog.getItem().getCode() + "未发现主单" + taskLog.getId());
                    }
                    //tasklog的出库数量回写
                    taskLog.setShipQty(taskLog.getMoveQty());
                    //pickdetail的出库数量回写
                    double shippedQtyF = Objects.isNull(pickDetail.getShippedQty()) ? 0d : pickDetail.getShippedQty() + taskLog.getShipQty();
                    pickDetail.setShippedQty(shippedQtyF);
                    //picktick的出库数量及状态回写
                    double shippedQtyZ = Objects.isNull(pickTicket.getShippedQuantity()) ? 0d : (pickTicket.getShippedQuantity() + taskLog.getShipQty());
                    pickTicket.setShipDate(new Timestamp(new Date().getTime()));
                    //发货单号 relatedBill2
                    if (Objects.isNull(pickTicket.getRelatedBill2())) {
                        pickTicket.setRelatedBill2(pickOut.getOrderNo());
                    } else {
                        pickTicket.setRelatedBill2(pickTicket.getRelatedBill2() + "," + pickOut.getOrderNo());
                    }
//                    pickTicket.setRelatedBill2(pickOut.getOrderNo());
                    pickTicket.setShippedQuantity(shippedQtyZ);
                    if (pickTicket.getPickedQuantity().intValue() - pickTicket.getShippedQuantity().intValue() <= 0) {
                        pickTicket.setStatus(BizStatus.SHIP_ALL);
                    } else {
                        pickTicket.setStatus(BizStatus.SHIP_PART);
                    }
                    //回写
                    taskLogService.update(taskLog);
                    pickDetailService.update(pickDetail);

//                    pickTicketService.update(pickTicket);
                    pickTicketRepository.updataPT(DateUtil.now(), pickTicket.getRelatedBill1(), pickTicket.getStatus(), pickTicket.getShippedQuantity(), pickTicket.getId());
                    pickOut.setDispatchQty(pickOut.getDispatchQty() + taskLog.getMoveQty());
                    if ((pickOut.getOrderQty() - pickOut.getDispatchQty()) == 0) {
                        pickOut.setStatus(BizStatus.SHIP_ALL);
                    } else {
                        pickOut.setStatus(BizStatus.SHIP_PART);
                    }
                    this.update(pickOut);
                    //扣库存
                    List<Inventory> inventories = inventoryService.queryInventory(pickTicket.getArea().getId(), taskLog.getDstPoint().getId(), taskLog.getItemKey().getId());
                    if (inventories.isEmpty()) {
                        throw new BadRequestException(HttpStatus.NOT_FOUND, taskLog.getItem().getCode() + "未发现库存数据");
                    }
                    Inventory inventory = inventories.get(0);
                    if (inventory.getQuantity() < taskLog.getMoveQty()) {
                        throw new BadRequestException(HttpStatus.NOT_FOUND, taskLog.getItem().getCode() + "库存不足单子出现问题");
                    }
                    inventoryLogService.storeInventoryLog(BizStatus.SHIPPING, BizStatus.REDUCE, null, inventory.getArea(), inventory.getItemKey(), inventory.getPoint(), inventory.getPoint(), inventory.getStock(), inventory.getStock(), inventory.getQuantity(), taskLog.getMoveQty(),
                            null, null, BizStatus.SHIPPING, inventory.getId(), inventory.getId(), inventory.getDescription());
                    inventory.setQuantity(inventory.getQuantity() - taskLog.getMoveQty());
                    inventory.setQueuedQty(inventory.getQueuedQty() - taskLog.getMoveQty());
                    if (inventory.getQuantity() > 0) {
                        inventoryService.update(inventory);
                    } else {
                        inventoryRepository.delete(inventory);
                    }
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmPickOutNotLog(Long pickOutId, Long pickTicketId) {//发货登记
        PickOut pickOut = pickOutRepository.getById(pickOutId);
        if (pickOut.getStatus().equals(BizStatus.SHIP_ALL)) {
            throw new BadRequestException(HttpStatus.NOT_FOUND, pickOut.getOrderNo() + "该单已全部发运");
        }
        List<TaskLog> taskLogs = taskLogRepository.getTaskLogByPickOutId(pickOutId);
        PickTicket pickTicket = pickTicketRepository.getById(pickTicketId);
        if (!taskLogs.isEmpty()) {
            for (TaskLog taskLog : taskLogs) {
                if ((taskLog.getMoveQty() - taskLog.getShipQty()) == 0d) {
                    continue;
                }
                //出库明细
                PickDetail pickDetail = taskLog.getTask().getPickDetail();
                if (Objects.isNull(pickDetail)) {
                    throw new BadRequestException(HttpStatus.NOT_FOUND, taskLog.getItem().getCode() + "未发现明细数据" + taskLog.getId());
                }
                //出库主表
                PickTicket pickTicket1 = taskLog.getTask().getPickDetail().getPickTicket();
                if (Objects.isNull(pickTicket1)) {
                    throw new BadRequestException(HttpStatus.NOT_FOUND, taskLog.getItem().getCode() + "未发现主单" + taskLog.getId());
                }
                if (!Objects.equals(pickTicket.getId(), pickTicket1.getId())) {
                    throw new BadRequestException(HttpStatus.NOT_FOUND, taskLog.getItem().getCode() + "主单不对");
                }
                //tasklog的出库数量回写
                taskLog.setShipQty(taskLog.getMoveQty());
                //pickdetail的出库数量回写
                double shippedQtyF = Objects.isNull(pickDetail.getShippedQty()) ? 0d : pickDetail.getShippedQty() + taskLog.getShipQty();
                pickDetail.setShippedQty(shippedQtyF);
                //picktick的出库数量及状态回写
                double shippedQtyZ = Objects.isNull(pickTicket.getShippedQuantity()) ? 0d : (pickTicket.getShippedQuantity() + taskLog.getShipQty());
                pickTicket.setShipDate(new Timestamp(new Date().getTime()));
                //发货单号 relatedBill2
                if (Objects.isNull(pickTicket.getRelatedBill2())) {
                    pickTicket.setRelatedBill2(pickOut.getOrderNo());
                }
                pickTicket.setShippedQuantity(shippedQtyZ);
                if (pickTicket.getPickedQuantity().intValue() - pickTicket.getShippedQuantity().intValue() <= 0) {
                    pickTicket.setStatus(BizStatus.SHIP_ALL);
                } else {
                    pickTicket.setStatus(BizStatus.SHIP_PART);
                }
                //回写
                taskLogService.update(taskLog);
                pickDetailService.update(pickDetail);
                pickTicketRepository.updataPT(DateUtil.now(), pickTicket.getRelatedBill1(), pickTicket.getStatus(), pickTicket.getShippedQuantity(), pickTicket.getId());
                pickOut.setDispatchQty(pickOut.getDispatchQty() + taskLog.getMoveQty());
                if ((pickOut.getOrderQty() - pickOut.getDispatchQty()) == 0d) {
                    pickOut.setStatus(BizStatus.SHIP_ALL);
                } else {
                    pickOut.setStatus(BizStatus.SHIP_PART);
                }
                this.update(pickOut);
            }
        }
    }

    public List<RPPickList> queryOutList(IScanPut t) {
        String sql = "select o.id outId, o.order_no code,o.plate_no cph,o.order_qty dds,o.dispatch_qty bhs,\n" +
                "DATE_FORMAT(o.create_time, '%Y-%m-%d') orderDate \n" +
                "from data_pick_out o \n" +
                "where 1=1 and (o.dispatch_qty<o.order_qty or o.dispatch_qty=0)";
        if (t.getScanCode() != null && !t.getScanCode().equals("")) {
            sql += " and o.order_no ='" + t.getScanCode() + "'";
        }
        sql += "ORDER BY o.order_no";
        List ts = entityManager.createNativeQuery(sql)
                .unwrap(SQLQuery.class)
                .setResultTransformer(
                        AliasToEntityMapResultTransformer.INSTANCE
                )
                .list();
        List<RPPickList> l = JSON.parseArray(JSON.toJSONString(ts), RPPickList.class);
        return l;
    }

    public List<PickOut> findByOut(String cph) {
        String hql = " from PickOut t where t.plateNo='" + cph + "' and (t.dispatchQty=0 or t.dispatchQty<t.orderQty)";
        Query query = entityManager.createQuery(hql);
        List<PickOut> outs = query.getResultList();
        return outs;
    }
}