/*
 *  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.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.youchain.basicdata.domain.Item;
import com.youchain.basicdata.domain.Point;
import com.youchain.basicdata.domain.Stock;
import com.youchain.basicdata.service.ItemService;
import com.youchain.basicdata.service.PointService;
import com.youchain.basicdata.service.StockService;
import com.youchain.businessdata.domain.*;
import com.youchain.businessdata.inputJson.OrderInfo;
import com.youchain.businessdata.inputJson.OrderParams;
import com.youchain.businessdata.service.*;
import com.youchain.businessdata.service.dto.OrderDto;
import com.youchain.exception.BadRequestException;
import com.youchain.modules.system.service.DictService;
import com.youchain.utils.*;
import lombok.RequiredArgsConstructor;
import com.youchain.businessdata.repository.MoRepository;
import com.youchain.businessdata.service.dto.MoDto;
import com.youchain.businessdata.service.dto.MoQueryCriteria;
import com.youchain.businessdata.service.mapstruct.MoMapper;
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.*;
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 2024-04-10
 **/
@Service
@RequiredArgsConstructor
public class MoServiceImpl implements MoService {

    private final MoRepository moRepository;
    private final MoMapper moMapper;
    private final EntityManager entityManager;
    private final OrderService orderService;
    private final MlsService mlsService;
    private final ItemService itemService;
    private final StockService stockService;
    private final PointService pointService;
    private final AgvTaskService agvTaskService;
    private final TaskService taskService;
    private final AsnDetailService asnDetailService;
    private final ItemKeyService itemKeyService;
    private final RedisObjectUtils redisObjectUtils;
    private final RedisUtils redisUtils;

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

    @Override
    public List<MoDto> queryAll(MoQueryCriteria criteria) {
        return moMapper.toDto(moRepository.findAll((root, criteriaQuery, criteriaBuilder) -> QueryHelp.getPredicate(root, criteria, criteriaBuilder)));
    }

    @Override
    @Transactional
    public MoDto findById(Integer id) {
        Mo mo = moRepository.findById(id).orElseGet(Mo::new);
        ValidationUtil.isNull(mo.getId(), "Mo", "id", id);
        return moMapper.toDto(mo);
    }

    @Override
    public MoDto findByLabelNo(String labelNo) {
        String hql = "from Mo where labelNo = :labelNo";
        Query query = entityManager.createQuery(hql);
        query.setParameter("labelNo", labelNo);
        List<Mo> list = query.getResultList();
        if (list.size() > 0) {
            return moMapper.toDto(list.get(0));
        } else {
            return null;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MoDto create(Mo resources) {
        return moMapper.toDto(moRepository.save(resources));
    }

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

    @Override
    public void deleteAll(Integer[] ids) {
        for (Integer id : ids) {
            moRepository.deleteById(id);
        }
    }

    @Override
    public void download(List<MoDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (MoDto mo : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("送货单头ID", mo.getDeliveryHeaderId());
            map.put("MO票", mo.getLabelNo());
            map.put("物料编码", mo.getItem().getCode());
            map.put("物料描述", mo.getItem().getName());
            map.put("可用数量", mo.getQty());
            map.put("标签类型", mo.getLabelType());
            map.put("是否有效", mo.getDeleteFlag());
            map.put("标签状态", mo.getLabelState());
            map.put("检验状态", mo.getCheckResult());
            map.put("mls子库", mo.getInvCode());
            map.put("mls入库时间", mo.getDatetimeStockIn());
            map.put("mls修改时间", mo.getMlsUpdateTime());
            map.put("mls创建时间", mo.getMlsCreateTime());
            map.put("wms接收时间", mo.getCreateTime());
            map.put("wms修改时间", mo.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public Mo toEntity(MoDto moDto) {
        return moMapper.toEntity(moDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean scanMo(Item item, Stock stock, Point srcPoint,String labelNo) {
        //条码格式；12227000016951-qth1847-240411422924

        // 验证条码格式
//        validateBarcodeFormat(mo);

//        String[] arr = mo.split("-");
//        String itemCode = arr[0];//物料编号
//        String stockCode = arr[1];//容器编号
//        String labelNo = arr[2];//标签号



        Point endPoint = redisObjectUtils.getOrThrow(Optional.ofNullable(pointService.findByCode(null, BaseStatus.FREE, BaseStatus.STORAGE, "存储区", null)), "存储区没有空闲点位!");

        // 获取MO票
        MoDto moDto = findByLabelNo(labelNo);
        // 验证送货单
        OrderDto orderDto =orderService.findByDeliveryHeaderId(moDto.getDeliveryHeaderId());
        // 验证送货单状态 和 是否检验
//        validateOrder(orderDto, moDto);

        // 生成AGV任务和入库任务
        createTasks(item, stock, srcPoint, endPoint, moDto.getLabelNo(), moDto, orderDto);
        stock.setName(labelNo);
        // 更新容器状态和目标点位状态
        updateStockAndEndPoint(stock, endPoint);

        return true;
    }

    private void validateBarcodeFormat(String mo) {
        if (mo.split("-").length != 3) {
            throw new IllegalArgumentException("条码格式错误!");
        }
    }



    private void validateStockStatus(Stock stock) {
        if (stock.getStatus().equals(BaseStatus.USED)) {
            throw new IllegalArgumentException(stock.getCode() + " 箱码已经有绑定关系!");
        }
    }

    private void validateLabelState(MoDto moDto) {
        if (!"PRINTED".equals(moDto.getLabelState())) {
            throw new IllegalArgumentException(moDto.getLabelNo() + " 标签已被接收(已接收状态)!");
        }
    }

    private void validateTask(MoDto moDto) {
        if (taskService.findByLabelNo(moDto.getLabelNo()).size() > 0) {
            throw new IllegalArgumentException(moDto.getLabelNo() + "此标签已入库!");
        }
    }

    private void validateOrder(OrderDto orderDto, MoDto moDto) {
       /* if (!orderDto.getDeliveryStatus().equals("lm_initial")) {
            throw new IllegalArgumentException(moDto.getLabelNo() + "标签背后的送货单" + orderDto.getBarcodeNumber() + "已取消(标签失效)!");
        }*/
        //获取送货单状态 验证检验状态
        OrderInfo orderInfo = getOrderInfo(orderDto.getDeliveryHeaderId()+"");
        String resultJson = mlsService.getOrderJson(orderInfo);
        JSONObject jsonObject=JSONObject.parseObject(resultJson);
        JSONObject data = jsonObject.getJSONObject("data");
        JSONArray list = data.getJSONArray("list");
        if (!list.isEmpty()){
            JSONObject itemAsn = list.getJSONObject(0);
            String iqcResult = itemAsn.getString("iqcResult")+"";
            String isIqcInspected = itemAsn.getString("isIqcInspected")+"";
            if (iqcResult.equals("ACCEPT")&&isIqcInspected.equals("Y")){

            }else {
                throw new IllegalArgumentException(moDto.getLabelNo() + "检验结果错误" + orderDto.getBarcodeNumber());
            }
        }
    }
    public OrderInfo getOrderInfo(String DeliveryHeaderId) {

        OrderParams params = new OrderParams();
        params.setOrgId(808);
        params.setPageSize(10);
        params.setDeliveryHeaderId(DeliveryHeaderId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setIfaceCode("MLS-WQ-002");
        orderInfo.setSourceSystem("WQ");
        orderInfo.setParams(params);
        return orderInfo;
    }
    @Override
    public Map<String, Mo> findBylabelNos(Set labelNos) {
        String hql = "from Mo where labelNo in (:labelNos) ";
        Query query = entityManager.createQuery(hql);
        query.setParameter("labelNos", labelNos);
        List<Mo> list = query.getResultList();
        Map<String, Mo> map = new HashMap<>();
        for (Mo mo : list) {
            map.put(mo.getLabelNo(), mo);
        }
        return map;
    }

    public void createTasks(Item item, Stock stock, Point srcPoint, Point endPoint, String propC1, MoDto moDto, OrderDto orderDto) {
        // 生成AGV任务
        AgvTask agvTask = new AgvTask(BizStatus.ASN, stock.getCode(), srcPoint.getCode(), endPoint.getCode(), BizStatus.OPEN, "PICKER_MOVE");
        agvTaskService.create(agvTask);

        // 生成入库任务

        AsnDetail asnDetail = asnDetailService.createAsnDetail(item, stock, srcPoint, propC1, moDto.getWorkOrderName());
        asnDetail.setOrderQty(moDto.getQty());
        asnDetail.setPo(moDto.getWorkOrderName());
        asnDetailService.create(asnDetail);

        //生成Itemkey
        ItemKey itemKey = itemKeyService.getItemKey(item, moDto.getLabelNo(), moDto.getWorkOrderName());

        //生成收货记录
        Task task = new Task(item, itemKey, orderDto.getBarcodeNumber(), BizStatus.ASN, asnDetail, null, null, null, stock, stock, srcPoint, endPoint, stock.getCode(), stock.getCode(), srcPoint.getCode(), endPoint.getCode(), null, BizStatus.OPEN, asnDetail.getOrderQty(), null, null, item.getDept(), agvTask);
        taskService.create(task);
        // 发送AGV任务
        List<AgvTask> agvTasks=new ArrayList<>();
        agvTasks.add(agvTask);
        String resultJson = agvTaskService.sendAgvTaskLXImpl(agvTasks);
        if (resultJson==null){
            throw new BadRequestException("fleet接口异常");
        }
        JSONObject resulObject = JSON.parseObject(resultJson);
        String code = resulObject.getString("code") == null ? "" : resulObject.getString("code");

        if (!code.equals("0")) {
            throw new RuntimeException("任务:"+agvTask.getJobForce()+"fleet接口返回错误"+resultJson);

        }
    }

    // 提取更新容器状态和目标点位状态的逻辑到单独方法
    private void updateStockAndEndPoint(Stock stock, Point point) {
        stock.setStatus(BaseStatus.USED);
        stock.setPoint(point);
        stockService.update(stock);
        point.setStatus(BaseStatus.USED);
        pointService.update(point);
    }
}
