package com.ruoyi.wms.controller;

import com.cmeim.common.core.exception.ServiceException;
import com.cmeim.common.core.utils.BeanUtil;
import com.cmeim.common.core.utils.DateUtil;
import com.cmeim.common.core.utils.ExcelExportUtil;
import com.cmeim.common.core.web.controller.GenericController;
import com.cmeim.common.core.web.domain.Respond;
import com.cmeim.common.core.web.domain.RespondEnum;
import com.cmeim.common.core.web.page.PageVo;
import com.ruoyi.wms.po.*;
import com.ruoyi.wms.repository.OrderInfoRepository;
import com.ruoyi.wms.repository.StationInfoRepository;
import com.ruoyi.wms.repository.ContainerInfoRepository;
import com.ruoyi.wms.repository.ContainerRecoderRepository;
import com.ruoyi.wms.service.ContainerService;
import com.google.common.collect.Lists;
import com.ruoyi.ruiYiController.annotation.Log;
import com.ruoyi.ruiYiController.enums.BusinessType;
import com.ruoyi.wms.vo.AgvTaskExportVo;
import com.ruoyi.wms.vo.ContainerInfoExportVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 李俊辉
 * @version 1.0
 * date: 2023/6/27
 */
@Api(tags = "周转箱")
@RestController
@Slf4j
@RequestMapping(value = "container")
public class ContainerController extends GenericController {
    @Autowired
    private ContainerInfoRepository containerInfoRepository;
    @Autowired
    private ContainerRecoderRepository containerRecoderRepository;
    @Autowired
    private ContainerService containerService;
    @Autowired
    private StationInfoRepository stationInfoRepository;
    @Autowired
    private OrderInfoRepository orderInfoRepository;

    private String hour="8";

    @ApiOperation(value = "列表")
    @GetMapping(value = "infoList")
    public Respond infoList(PageVo pv, ContainerInfo containerInfo) {
        PageRequest pageRequest = PageRequest.of(pv.getPageNo() - 1, pv.getPageSize(),
                Sort.by(sortOrder(containerInfo.getOrders())));
        Page page = containerInfoRepository.findAll(buildSpecification(containerInfo), pageRequest);
        List<ContainerInfo> list = page.getContent();
        pv.setRecordsTotal(page.getTotalElements());
        pv.setData(list);
        return buildSuccess(pv);
    }

    @ApiOperation(value = "列表")
    @GetMapping(value = "findByContainerNumber")
    public Respond findByContainerNumber(String containerNumber) {
        ContainerInfo containerInfo = containerInfoRepository.findByContainerNumber(containerNumber);
        return buildSuccess(containerInfo);
    }

    @ApiOperation(value = "查询周转箱绑定工单的物料信息")
    @GetMapping(value = "findOrderByContainerNumber")
    public Respond findOrderByContainerNumber(String containerNumber) {
        ContainerInfo containerInfo = containerInfoRepository.findByContainerNumber(containerNumber);
        if (containerInfo != null) {
            OrderInfo orderInfo = orderInfoRepository.findByProductionTask(containerInfo.getProductionTask());
            return buildSuccess(orderInfo);
        } else {
            return buildFailure("未找到该周转箱号：" + containerNumber);
        }
    }

    @ApiOperation(value = "导出excel")
    @PostMapping("exportExcel")
    public void export(ContainerInfo containerInfo, HttpServletResponse response) throws Exception {
        List<ContainerInfo> list = containerInfoRepository.findAll(buildSpecification(containerInfo));
        List<ContainerInfoExportVo> exportList = new ArrayList<>();
        for(ContainerInfo container:list){
            ContainerInfoExportVo containerInfoExportVo = BeanUtil.copyProperties(container, ContainerInfoExportVo.class);
            exportList.add(containerInfoExportVo);
        }
        // 创建工作簿对象
        SXSSFWorkbook workbook = new SXSSFWorkbook(1000);
        // 创建工作表
        SXSSFSheet sheet = workbook.createSheet("周转箱列表");

        String[] rowsName = new String[]{"序号","周装箱号","周装箱状态","装表数量","库位编码","开始入库时间","机器人放到库位上时间","开始出库时间","出库时间","生产任务单","创建人","创建时间","更新人","更新时间"};
        List<Object[]> dataList = new ArrayList<Object[]>();
        Object[] objs = null;
        int i = 1;
        for (ContainerInfoExportVo vo : exportList) {
            if(vo.getContainerStatus() == 5){
                vo.setContainerStatusShow("空闲(库外)");
            }else if(vo.getContainerStatus() == 10){
                vo.setContainerStatusShow("空闲(库内)");
            }else if(vo.getContainerStatus() == 15){
                vo.setContainerStatusShow("入库中(手动)");
            }else if(vo.getContainerStatus() == 20){
                vo.setContainerStatusShow("入库中(自动)");
            }else if(vo.getContainerStatus() == 25){
                vo.setContainerStatusShow("入库中(空箱)");
            }else if(vo.getContainerStatus() == 30){
                vo.setContainerStatusShow("在库");
            } else if(vo.getContainerStatus() == 35){
                vo.setContainerStatusShow("出库中");
            }

            objs = new Object[rowsName.length];
            objs[0] = i;
            objs[1] = vo.getContainerNumber();
            objs[2] = vo.getContainerStatusShow();
            objs[3] = vo.getQty();
            objs[4] = vo.getStoreCode();
            objs[5] = vo.getOnInstoreTime();
            objs[6] = vo.getInstoreTime();
            objs[7] = vo.getOnOutstoreTime();
            objs[8] = vo.getOutstoreTime();
            objs[9] = vo.getProductionTask();
            objs[10] = vo.getCreatedBy();
            objs[11] = vo.getCreatedDt();
            objs[12] = vo.getUpdatedBy();
            objs[13] = vo.getUpdatedDt();
            dataList.add(objs);
            i += 1;
        }
        ExcelExportUtil.getExportWorkbook(workbook, sheet, rowsName, dataList);
        ExcelExportUtil.sendHttpResponse(response, "Container", workbook);
    }

    @ApiOperation(value = "列表")
    @GetMapping(value = "recorderList")
    public Respond recorderList(PageVo pv, ContainerRecoder containerRecoder) {
        PageRequest pageRequest = PageRequest.of(pv.getPageNo() - 1, pv.getPageSize(),
                Sort.by(sortOrder(containerRecoder.getOrders())));
        Page page = containerInfoRepository.findAll(buildSpecification2(containerRecoder), pageRequest);
        List<ContainerRecoder> list = page.getContent();
        pv.setRecordsTotal(page.getTotalElements());
        pv.setData(list);
        return buildSuccess(pv);
    }

    @ApiOperation(value = "修改周转箱状态，修订周转箱数量，绑定任务单，修改任务单入库中数量")
    @Log(title = "周转箱", businessType = BusinessType.UPDATE)
    @PostMapping(value = "updateContainerStatus")
    public Respond updateContainerStatus(@RequestBody ContainerInfo containerInfo) {
        ContainerInfo container = containerInfoRepository.findByContainerNumber(containerInfo.getContainerNumber());
        if (container == null) {
            ContainerInfo newContainerInfo = new ContainerInfo();
            newContainerInfo.setContainerNumber(containerInfo.getContainerNumber());
            newContainerInfo.setQty(0);
            newContainerInfo.setIsPdaEdit(0);
            newContainerInfo.setCreatedBy(containerInfo.getUpdatedBy());
            newContainerInfo.setCreatedDt(DateUtil.getCurrentDate());
            newContainerInfo.setContainerStatus(5);
            container = containerInfoRepository.save(newContainerInfo);
        }
        if (containerInfo.getContainerStatus() == 10 || containerInfo.getContainerStatus() == 30 || containerInfo.getContainerStatus() == 35) {
            throw new ServiceException(RespondEnum.PARAMETER_ERROR, "该周转箱状态不能进行入库");
        }
        if (container.getContainerStatus() == 15 || container.getContainerStatus() == 20 ||container.getContainerStatus() == 25) {
            return buildSuccess();
        }
        if (StringUtils.isBlank(containerInfo.getStationCode())) {
            throw new ServiceException(RespondEnum.PARAMETER_ERROR, "站位编码为空");
        }
        if (StringUtils.isBlank(containerInfo.getProductionTask())) {
            containerInfo.setProductionTask(null);
        } else {
            //查询正在执行的任务单，绑定任务单
            StationInfo stationInfo = stationInfoRepository.findByStationCode(containerInfo.getStationCode());
            containerInfo.setProductionTask(stationInfo.getProductionTask());
            //修订周转箱数量
            List<ContainerInfo> containerInfoList = containerInfoRepository.findByProductionTask(stationInfo.getProductionTask());
            Integer sumQty = containerInfoList.stream().collect(Collectors.summingInt(ContainerInfo::getQty));
            OrderInfo orderInfo = orderInfoRepository.findByProductionTask(stationInfo.getProductionTask());
            if (orderInfo.getPlanQty() - sumQty == 0) {
                throw new ServiceException(RespondEnum.PARAMETER_ERROR, "该生产任务单已经入库完毕，请切换工单！");
            }
            if (orderInfo.getPlanQty() - sumQty < 6) {
                container.setQty(orderInfo.getPlanQty() - sumQty);
            } else {
                container.setQty(containerInfo.getQty());
            }
            //修改任务单中的入库中数量
            if (orderInfo != null) {
                orderInfo.setOngoingQty(orderInfo.getOngoingQty() + container.getQty());
                orderInfoRepository.save(orderInfo);
            }
        }
        //赋值其他属性
        container.setContainerStatus(containerInfo.getContainerStatus());
        container.setProductionTask(containerInfo.getProductionTask());
        container.setUpdatedBy(containerInfo.getUpdatedBy());
        container.setUpdatedDt(containerInfo.getUpdatedDt());
        ContainerInfo save = containerInfoRepository.save(container);


        return buildSuccess(save);
    }

    @ApiOperation(value = "PDA修改周转箱状态，修订周转箱数量，绑定任务单，修改任务单入库中数量")
    @Log(title = "周转箱", businessType = BusinessType.UPDATE)
    @PostMapping(value = "updateContainerStatusForPda")
    public Respond updateContainerStatusForPda(@RequestBody ContainerInfo containerInfo) {
        ContainerInfo container = containerInfoRepository.findByContainerNumber(containerInfo.getContainerNumber());
        if (container == null) {
            throw new ServiceException(RespondEnum.PARAMETER_ERROR, "未找到该周转箱");
        }
        if (containerInfo.getContainerStatus() == 10 || containerInfo.getContainerStatus() == 30 || containerInfo.getContainerStatus() == 35) {
            throw new ServiceException(RespondEnum.PARAMETER_ERROR, "该周转箱状态不能进行入库");
        }
        if (StringUtils.isBlank(containerInfo.getStationCode())) {
            throw new ServiceException(RespondEnum.PARAMETER_ERROR, "站位编码为空");
        }
        if (StringUtils.isBlank(containerInfo.getProductionTask())) {
            throw new ServiceException(RespondEnum.PARAMETER_ERROR, "生产任务单为空");
        }
        //查询正在执行的任务单，绑定任务单
        StationInfo stationInfo = stationInfoRepository.findByStationCode(containerInfo.getStationCode());
        containerInfo.setProductionTask(stationInfo.getProductionTask());
        //修订周转箱数量
        List<ContainerInfo> containerInfoList = containerInfoRepository.findByProductionTask(stationInfo.getProductionTask());
        Integer sumQty = containerInfoList.stream().collect(Collectors.summingInt(ContainerInfo::getQty));
        OrderInfo orderInfo = orderInfoRepository.findByProductionTask(stationInfo.getProductionTask());
        //赋值其他属性
        container.setContainerStatus(containerInfo.getContainerStatus());
        container.setQty(containerInfo.getQty());
        if (orderInfo.getPlanQty() - sumQty < 6) {
            container.setQty(orderInfo.getPlanQty() - sumQty);
        }
        container.setIsPdaEdit(1);
        container.setProductionTask(containerInfo.getProductionTask());
        container.setUpdatedBy(containerInfo.getUpdatedBy());
        container.setUpdatedDt(containerInfo.getUpdatedDt());
        ContainerInfo save = containerInfoRepository.save(container);

        //修改任务单中的入库中数量
        if (orderInfo != null) {
            orderInfo.setOngoingQty(orderInfo.getOngoingQty() + save.getQty());
            orderInfoRepository.save(orderInfo);
        }
        return buildSuccess(save);
    }

    @ApiOperation(value = "清空周转箱")
    @GetMapping(value = "modifyContainerInfo")
    public Respond modifyContainerInfo(String containerNumber, String updatedBy) {
        ContainerInfo containerInfo = containerInfoRepository.findByContainerNumber(containerNumber);
        if (containerInfo != null) {
            if (StringUtils.isNotBlank(containerInfo.getProductionTask())) {
                OrderInfo orderInfo = orderInfoRepository.findByProductionTask(containerInfo.getProductionTask());
                if (containerInfo.getContainerStatus() == 35) {
                    orderInfo.setOutQty(orderInfo.getOutQty() + containerInfo.getQty());
                    orderInfo.setUpdatedBy(updatedBy);
                    orderInfo.setUpdatedDt(DateUtil.getCurrentDate());
                    orderInfoRepository.save(orderInfo);
                } else if (containerInfo.getContainerStatus() == 20 || containerInfo.getContainerStatus() == 15) {
                    orderInfo.setOngoingQty(orderInfo.getOngoingQty() - containerInfo.getQty());
                    orderInfo.setUpdatedBy(updatedBy);
                    orderInfo.setUpdatedDt(DateUtil.getCurrentDate());
                    orderInfoRepository.save(orderInfo);
                }
            }
            containerInfo.setQty(0);
            containerInfo.setContainerStatus(5);
            containerInfo.setStoreCode(null);
            containerInfo.setProductionTask(null);
            containerInfo.setInstoreTime(null);
            containerInfo.setUpdatedBy(updatedBy);
            containerInfo.setUpdatedDt(DateUtil.getCurrentDate());
            containerInfoRepository.save(containerInfo);
        }
        return buildSuccess();
    }

    @ApiOperation(value = "查询大于规定小时的任务单及数量")
    @PostMapping(value = "findGreaterThanEightHours")
    public Respond findGreaterThanEightHours() {
        List<ContainerInfo> containerInfoList = containerService.queryGreaterThanEightHours();
        //根据生产任务单进行分组求和
        Map<String, Integer> sumMap = containerInfoList.stream()
                .collect(Collectors.groupingBy(ContainerInfo::getProductionTask, Collectors.summingInt(ContainerInfo::getQty)));
        return buildSuccess(sumMap);
    }

    private Specification buildSpecification(ContainerInfo containerInfo) {
        Specification<ContainerInfo> specification = new Specification<ContainerInfo>() {
            @Override
            public Predicate toPredicate(Root<ContainerInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = Lists.newArrayList();
                if (containerInfo.getContainerNumber() != null) {
                    predicates.add(cb.like(root.get("containerNumber").as(String.class), "%" + containerInfo.getContainerNumber() + "%"));
                }
                if (containerInfo.getStoreCode() != null) {
                    predicates.add(cb.like(root.get("storeCode").as(String.class), "%" + containerInfo.getStoreCode() + "%"));
                }
                if(containerInfo.getProductionTask()!=null)
                {
                    predicates.add(cb.like(root.get("productionTask").as(String.class), "%" + containerInfo.getProductionTask() + "%"));
                }
                if (containerInfo.getContainerStatus() != null) {
                    predicates.add(cb.equal(root.get("containerStatus").as(Integer.class), containerInfo.getContainerStatus()));
                }
                if (containerInfo.getContainerStatusArr() != null) {
                    CriteriaBuilder.In<Integer> in = cb.in(root.get("containerStatus").as(Integer.class));
                    for (Integer status : containerInfo.getContainerStatusArr()) {
                        in.value(status);
                    }
                    predicates.add(in);
                }
                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        return specification;
    }

    private Specification buildSpecification2(ContainerRecoder containerRecoder) {
        Specification<ContainerRecoder> specification = new Specification<ContainerRecoder>() {
            @Override
            public Predicate toPredicate(Root<ContainerRecoder> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
                List<Predicate> predicates = Lists.newArrayList();
                if (containerRecoder.getContainerNumber() != null) {
                    predicates.add(cb.like(root.get("containerNumber").as(String.class), "%" + containerRecoder.getContainerNumber() + "%"));
                }
                if (containerRecoder.getContainerStatus() != null) {
                    predicates.add(cb.equal(root.get("containerStatus").as(Integer.class), containerRecoder.getContainerStatus()));
                }
                if (containerRecoder.getContainerStatusArr() != null) {
                    CriteriaBuilder.In<Integer> in = cb.in(root.get("containerStatus").as(Integer.class));
                    for (Integer status : containerRecoder.getContainerStatusArr()) {
                        in.value(status);
                    }
                    predicates.add(in);
                }
                return cb.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        return specification;
    }
}
