/*
 *  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.alibaba.fastjson.JSON;
import com.youchain.basicdata.domain.*;
import com.youchain.basicdata.repository.AreaRepository;
import com.youchain.basicdata.repository.AutomaticPlanningRepository;
import com.youchain.basicdata.repository.BoxRepository;
import com.youchain.basicdata.service.ItemService;
import com.youchain.basicdata.service.PointService;
import com.youchain.basicdata.service.dto.ItemDto;
import com.youchain.businessdata.domain.Inventory;
import com.youchain.businessdata.domain.PickDetail;
import com.youchain.businessdata.domain.PickTicket;
import com.youchain.businessdata.domain.Task;
import com.youchain.businessdata.repository.InventoryRepository;
import com.youchain.businessdata.repository.PickTicketRepository;
import com.youchain.businessdata.repository.TaskRepository;
import com.youchain.businessdata.returnJson.RPTaskList;
import com.youchain.businessdata.service.InventoryService;
import com.youchain.businessdata.service.PickTicketService;
import com.youchain.businessdata.service.TaskService;
import com.youchain.businessdata.service.dto.PickDetailZscDto;
import com.youchain.businessdata.service.dto.PickTicketDto;
import com.youchain.businessdata.service.mapstruct.PickTicketMapper;
import com.youchain.exception.BadRequestException;
import com.youchain.modules.system.domain.Dept;
import com.youchain.modules.system.domain.Job;
import com.youchain.modules.system.repository.JobRepository;
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 lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.core.utils.JsonUtil;
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.text.SimpleDateFormat;
import java.util.*;
import java.io.IOException;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.servlet.http.HttpServletResponse;

/**
 * @author huojin
 * @website https://eladmin.vip
 * @description 服务实现
 * @date 2023-08-16
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class PickDetailServiceImpl implements PickDetailService {
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH");
    private final PickDetailRepository pickDetailRepository;
    private final PickDetailMapper pickDetailMapper;
    private final InventoryRepository inventoryRepository;
    private final TaskRepository taskRepository;
    private final ItemService itemService;
    private final TaskService taskService;
    private final EntityManager entityMapper;
    private final PickTicketRepository pickTicketRepository;
    private final PointService pointService;
    private final InventoryService inventoryService;
    private final EntityManager entityManager;
    private final AutomaticPlanningRepository automaticPlanningRepository;
    private final JobRepository jobRepository;
    private final AreaRepository areaRepository;

    @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());
        //订单数量的调整
        PickTicket pickTicket = resources.getPickTicket();
        PickDetailDto byId = this.findById(resources.getId());
        pickTicket.setOrderQuantity(pickTicket.getOrderQuantity() - byId.getOrderQty() + resources.getOrderQty());
        pickTicketRepository.updataOrderQuantity(pickTicket.getOrderQuantity(),pickTicket.getId());
        pickDetail.copy(resources);
        pickDetailRepository.save(pickDetail);
    }

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

    public void deletePickDetail(Long id){
        //扣主表的订单数量
        PickDetail detail = pickDetailRepository.getById(id);
        PickTicket pt=detail.getPickTicket();
        Boolean bcbl=Boolean.FALSE;
        if(pt.getBillType().getName().equals(BaseStatus.BT_BCBL)){
            bcbl=Boolean.TRUE;
        }
        if(detail.getAllocatedQty()+detail.getBcQty()>0){
            throw new BadRequestException("已出单，不能删除");
        }
        if(bcbl){
            PickDetail oldDetail=pickDetailRepository.getById(detail.getSourceId());
            if(oldDetail!=null){
                oldDetail.setBcQty(oldDetail.getBcQty()- detail.getOrderQty());
                this.update(oldDetail);
            }
        }
        pt.setOrderQuantity(pt.getOrderQuantity()-detail.getOrderQty());
       // pickTicketService.update(pt);
        pickTicketRepository.save(pt);
        pickDetailRepository.deleteById(id);
    }

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void allocate(long id, double quantity){
        PickDetailDto pickDetailDto = findById(id);
        PickDetail pd = toEntity(pickDetailDto);//Dto转实体
        PickTicket pickTicket = pd.getPickTicket();
        ItemDto itemDto = pickDetailDto.getItem();
        Item item = itemService.toEntity(itemDto);
        if (pd.getOrderQty() > pd.getAllocatedQty()) {
            Long zzkwId=null;
            if(pd.getPoint()!=null&&pickTicket.getArea().getBexb()){
                zzkwId=pd.getPoint().getId();
            }
            List<Inventory> invs = inventoryService.queryInventoryAllocate(item.getId(), pickTicket.getArea().getId(),zzkwId);
            if (invs.size() > 0) {
                double allocateQty = 0;
                double unQty = quantity;//未分配数量
                double srs=0;
                for (Inventory inv : invs) {
                    Point startPoint = inv.getPoint();//原库位
                    String areaCode="S仓";
                    if(startPoint.getArea().equals("A仓")){
                        areaCode="A仓";
                    }
                    Point endPoint = pointService.getPoint(null, null, BaseStatus.BHZC, areaCode);//目标库位
                    if(endPoint==null){
                        throw new BadRequestException(HttpStatus.NOT_FOUND, "请维护备货暂存区");
                    }
                    if (unQty <= 0) {
                        break;
                    }
                    allocateQty = inv.getQuantity() - inv.getQueuedQty();//库存可用数量
                    if (allocateQty <= 0) {
                        continue;
                    }
                    //本次拣货数小于收容数则按照收容数进行分配,只有正常备货单才走该逻辑
                    if(pickTicket.getCode().indexOf("BH")>=0||pickTicket.getCode().indexOf("BC")>=0) {
                        if (unQty < srs) {
                            if (allocateQty >= srs) {
                                unQty = srs;
                            } else {
                                //unQty = allocateQty;
                            }
                        }
                    }
                    if (unQty < allocateQty) {
                        allocateQty = unQty;
                    }
                    inv.setQueuedQty(inv.getQueuedQty() + allocateQty);
                    inventoryRepository.save(inv);
                    unQty -= allocateQty;
                    pd.setAllocatedQty(pd.getAllocatedQty() + allocateQty);
                    pickDetailRepository.save(pd);
                    pickTicket.setAllocatedQuantity(pickTicket.getAllocatedQuantity() + allocateQty);
                    if (pickTicket.getAllocatedQuantity()>0) {
                        pickTicket.setStatus(BizStatus.ALLOCATE);
                    }
                    //备货表上出单日期（审核写）
                    pickTicket.setOutOrderDate(new Timestamp(new Date().getTime()));
                    pickTicketRepository.save(pickTicket);
                    Task task = taskService.storeTask(null,pd,pickTicket.getArea(),inv.getItemKey(),startPoint,endPoint,allocateQty);
                }
            }
        } else {
            throw new BadRequestException(HttpStatus.NOT_FOUND,"已分配,请勿重复操作！");
        }

    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void cancelAllocate(long id){
        PickDetailDto pickDetailDto = findById(id);
        PickDetail pd = toEntity(pickDetailDto);
        List<Task> Tasks = taskRepository.getPickNotAllTask(id);
        for (Task task : Tasks) {
            //根据Taskz找到对应的库存
            double quantity=task.getPlanQty();
            Inventory inv = inventoryRepository.findById(task.getInvId()).get();
            inv.setQueuedQty(inv.getQueuedQty() - quantity);
            inventoryRepository.save(inv);
            //删除Task
            taskRepository.delete(task);
            pd.setAllocatedQty(pd.getAllocatedQty() - quantity);
            pd.setPureXqBz(pd.getPropC4()-pd.getAllocatedQty());
            if (pd.getAllocatedQty() <= 0) {
                pd.setAllocatedQty(0d);
                pd.setStatus(BizStatus.OPEN);
            }
            this.update(pd);
            pickDetailRepository.save(pd);

        }

    }

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

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

    public List<Object[]> queryOut(String type, String date) {
        String hql = "";
        if (type.equals("Day")) {
            hql = "select sum(d.orderQty),sum(d.pickedQty) from PickDetail d " +
                    " where DATE_FORMAT(d.createTime,'%Y-%m-%d')=DATE_FORMAT(now(),'%Y-%m-%d')";
        } else if (type.equals("Month")) {
            hql = "select sum(d.orderQty),sum(d.pickedQty) from PickDetail d " +
                    " where DATE_FORMAT(d.createTime,'%Y-%m')=DATE_FORMAT(now(),'%Y-%m')";
        } else if (type.equals("InOutDay")) {
            hql = "select DATE_FORMAT(d.createTime,'%Y-%m-%d'),sum(d.pickedQty) from PickDetail d " +
                    " where DATE_FORMAT(d.createTime,'%Y-%m-%d')>='" + date + "' " +
                    " group by DATE_FORMAT(d.createTime,'%Y-%m-%d')";
        }
        Query query = entityMapper.createQuery(hql);
        List<Object[]> ts = query.getResultList();
        return ts;
    }

    @Override
    public PickDetail createPickDetail(PickTicket pt,Item item, String po,double qty,String supplier) {
        PickDetail d = new PickDetail();
        d.setItem(item);
        d.setLineNo(1l);
        d.setStatus(BizStatus.OPEN);
        d.setOrderQty(qty);
        d.setDept(item.getDept());
        d.setPo(po);
        d.setPickTicket(pt);
        d.setSupplier(supplier);
        pickDetailRepository.save(d);
        return d;
    }

    @Override
    public List<PickDetail> queryPickDetailList(long picktickId) {
        String hql = " from PickDetail pd where pd.pickTicket.id=" + picktickId + " and pd.orderQty-pd.allocatedQty>0 ";
        Query query = entityMapper.createQuery(hql);
        List<PickDetail> queryResultList = query.getResultList();
        return queryResultList;
    }
    public  List<PickDetailZscDto> queryZscAll(PickDetailQueryCriteria criteria) {
        Query query = getQuery(criteria);
        List ts= query
                .unwrap(SQLQuery.class)
                .setResultTransformer(
                        AliasToEntityMapResultTransformer.INSTANCE
                )
                .list();
        List<PickDetailZscDto> list = JSON.parseArray(JSON.toJSONString(ts),PickDetailZscDto.class);
        return list;
    }


    public  Map<String,Object> queryPickDetailAll(PickDetailQueryCriteria criteria, Pageable pageable) {
        int pageNum=pageable.getPageNumber();//当前页
        int pageSize=pageable.getPageSize();//条数
        Query query = getQuery(criteria);
        int pageCount=query.getResultList().size();
        query.setFirstResult((pageNum)*pageSize);
        query.setMaxResults((pageNum+1)*pageSize);
        List<PickDetailZscDto> queryResultList = query.unwrap(SQLQuery.class)
                .setResultTransformer(
                        AliasToEntityMapResultTransformer.INSTANCE
                )
                .list();
        Map<String,Object> map=new HashMap<>();
        map.put("content",queryResultList);
        map.put("totalElements",pageCount);
        return map;
    }
    public Query getQuery(PickDetailQueryCriteria criteria){
        String sql = "SELECT * from (select pd.id,pt.id  pt_id,pt.`code`,rk.gc_code,rk.name rk_name,rk.code rk_code,ck.code ck_code,ck.name ck_name,pt.`status`,pt.order_date,it.code item_code,it.name item_name,it.unit,\n" +
                "pd.xq_qty,it.extend_d3,pd.prop_c4,(pd.order_qty-pd.allocated_qty-pd.bc_qty) as pure_xq_bz,pd.order_qty,pd.bc_qty," +
                "(pd.order_qty-pd.allocated_qty) wcd_qty,pd.allocated_qty,pd.picked_qty,pd.shipped_qty,pd.xb_qty,\n" +
                "pd.supplier,pd.contents,pd.ac,zzkw.`code` zzkw_code,pd.remark,\n" +
                "(select max(dl.new_item_code) from data_design_list dl where dl.old_item_id=it.id  and dl.new_item_code is not null and pd.allocated_qty=0 and pd.bc_qty=0 and SUBSTR(dl.implementation_date,1,6)=DATE_FORMAT(pt.order_date,'%Y%m')) as sb_item_code,\n" +
                "(select IFNULL(sum(inv.quantity-inv.queued_qty),0) from data_inventory inv left join data_item_key ik on ik.id=inv.item_key_id where ik.item_id=it.id and inv.area_id=pt.area and inv.point_id not in (144,145)) as inv_qty\n" +
                " FROM `data_pick_detail` pd \n" +
                "left join data_pick_ticket pt on pt.id=pd.pick_ticket_id\n" +
                "left join base_item it on it.id=pd.item_id\n" +
                "left join base_area rk on rk.id=pd.sh_area_id\n" +
                "left join base_area ck on ck.id=pd.area_id\n" +
                "left join base_point zzkw on zzkw.id=pd.point_id )t \n" +
                "where 1=1 and t.code like 'B%'";
        if(criteria!=null) {
            if (criteria.getCode()!=null &&!criteria.getCode().equals("") ) {
                sql += " and t.code like '%" + criteria.getCode() + "%'";
            }
            if (criteria.getItemCode()!=null &&!criteria.getItemCode().equals("") ) {
                sql += " and t.item_code like '%" + criteria.getItemCode() + "%'";
            }
            if (criteria.getItemName()!=null &&!criteria.getItemName().equals("") ) {
                sql += " and t.item_name like '%" + criteria.getItemName() + "%'";
            }
            if (criteria.getRkAreaCode()!=null &&!criteria.getRkAreaCode().equals("") ) {
                sql += " and t.rk_code like '%" + criteria.getRkAreaCode() + "%'";
            }
            if (criteria.getGcCode()!=null &&!criteria.getGcCode().equals("") ) {
                sql += " and t.gc_code like '%" + criteria.getGcCode() + "%'";
            }
            if (criteria.getCkAreaCode()!=null &&!criteria.getCkAreaCode().equals("") ) {
                sql += " and t.ck_code like '%" + criteria.getCkAreaCode() + "%'";
            }
            if (criteria.getPureXqBz()!=null &&!criteria.getPureXqBz().equals("") ) {
                sql += " and t.pure_xq_bz>="+criteria.getPureXqBz();
            }
            if (criteria.getStatus()!=null &&!criteria.getStatus().equals("") ) {
                sql += " and t.status='"+criteria.getStatus()+"'";
            }
            if (criteria.getInvQty()!=null &&!criteria.getInvQty().equals("") ) {
                sql += " and t.inv_qty>="+criteria.getInvQty();
            }
            if (criteria.getCreateTime()!=null) {
                sql += " and t.order_date BETWEEN '"+criteria.getCreateTime().get(0)+"' and '"+criteria.getCreateTime().get(1)+"'";
            }
        }
        sql+=" order by t.pt_id desc";
        Query query = entityManager.createNativeQuery(sql);
        return query;
    }

    public  List<Object[]> getQueryBcbl(Date blDate,Long ckAreaId,String gc){
        String sql="select pd.id,ck.id ck_id," +
                "(select IFNULL(sum(inv.quantity-inv.queued_qty),0) from data_inventory inv left join data_item_key ik on ik.id=inv.item_key_id where ik.item_id=it.id and inv.area_id=pt.area and inv.quantity>0) as inv_qty\n" +
                " FROM `data_pick_detail` pd \n" +
                "left join data_pick_ticket pt on pt.id=pd.pick_ticket_id\n" +
                "left join base_item it on it.id=pd.item_id\n" +
                "left join base_area rk on rk.id=pt.sh_area\n" +
                "left join base_area ck on ck.id=pt.area\n" +
                " where 1=1  and (pd.allocated_qty+pd.bc_qty)<pd.order_qty and pt.code like 'BH%' and pt.pc!='手工维护' and pt.gc_code='"+gc+"' and pt.area="+ckAreaId;
       // sql+=" and  pt.allocated_quantity>0 ";
        //查找工位最后的上线计划修改日期
//        sql+=" and pt.order_date>=(CURDATE() - INTERVAL 1 DAY) ";
        sql+=" and DATE_FORMAT(pt.order_date,'%Y-%m-%d')='"+DateUtil.dateYmd(blDate)+"'";
        Long user_id=SecurityUtils.getCurrentUserId();
        List<Job> jobs=jobRepository.jobAreaCodes(user_id);
        if(jobs.size()>0){
            String areaCode= jobs.get(0).getAreaCode();
            Area area=areaRepository.getByCode(areaCode);
            sql+=" and ck.id="+ area.getId();
        }
//        sql+=" and rk.id="+ automaticPlanning.getShArea().getId();
        String split_sql = "SELECT t.id,t.ck_id from ("+sql+") t " +
                " where 1=1 and t.inv_qty>0  order by t.id asc";
//        log.info("query:"+split_sql);
        Query query = entityManager.createNativeQuery(split_sql);
        List<Object[]> queryResultList = query.getResultList();
//        List<PickDetailZscDto> queryResultList = query.unwrap(SQLQuery.class)
//                .setResultTransformer(
//                        AliasToEntityMapResultTransformer.INSTANCE
//                )
//                .list();
        return queryResultList;
    }
    public Double getMaxBomQty(long picktickId,String largeClass) {
        String hql = "select max(pd.orderQty) from PickDetail pd where pd.pickTicket.id=" + picktickId + " and pd.item.largeClass='"+largeClass+"'";
        Query query = entityMapper.createQuery(hql);
        Double result =(Double)query.getResultList().get(0);
        return result;
    }

    public List<PickDetail> getBomList(long picktickId,String largeClass) {
        String hql = " from PickDetail pd where pd.pickTicket.id=" + picktickId + " and pd.item.largeClass='"+largeClass+"'";
        Query query = entityMapper.createQuery(hql);
        List<PickDetail> queryResultList = query.getResultList();
        return queryResultList;
    }

}
