/*
 *  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.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.service.*;
import com.youchain.businessdata.service.dto.OrderDto;
import com.youchain.exception.EntityExistException;
import com.youchain.exception.handler.ApiResult;
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.data.domain.Example;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
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;

import static org.springframework.http.HttpStatus.BAD_REQUEST;

/**
 * @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 ItemService itemService;
    private final StockService stockService;
    private final InventoryService inventoryService;
    private final PointService pointService;
    private final AgvTaskService agvTaskService;
    private final TaskService taskService;
    private final AsnDetailService asnDetailService;
    private final ItemKeyService itemKeyService;
    private final DictService dictService;

    @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  void scanMo(String mo) {
        //条码格式；12227000016951-qth1847-240411422924

        String[] arr = mo.split("-");
        if (arr.length != 3) {
            throw new RuntimeException("条码格式错误!");
        }

        String itemCode = arr[0];//物料编号
        String stockCode = arr[1];//容器编号
        String labelNo = arr[2];//标签号

        Item item = itemService.existItem(itemCode);
        if (item == null) {
            throw new RuntimeException(itemCode + "系统无此物料!");
        }

        Stock stock = stockService.findByCode(stockCode, null);
        if (stock == null) {
            throw new RuntimeException(stockCode + "系统无此容器!");
        }


        if (stock.getStatus().equals(BaseStatus.USED)) {
            throw new RuntimeException(stockCode + "箱码已经有绑定关系!");
        }


        Point srcPoint = pointService.findByCode(null, null, null, "入库接驳口", null);
        if (srcPoint == null) {
            throw new RuntimeException("系统无入库接驳口!");
        }

        Point endPoint = pointService.findByCode(null, BaseStatus.FREE, BaseStatus.STORAGE, "存储区", null);
        if (endPoint == null) {
            throw new RuntimeException("存储区没有空闲点位!");
        }

        MoDto moDto = this.findByLabelNo(labelNo);
        if (moDto == null) {
            throw new RuntimeException(labelNo + "系统无此标签!");
        }

        if (!moDto.getLabelState().equals("PRINTED")) {
            throw new RuntimeException(labelNo + "标签已被接收(已接收状态)!");
        }

        if (taskService.findByLabelNo(labelNo).size() > 0) {
            throw new RuntimeException(labelNo + "此标签已入库!");
        }

        OrderDto orderDto = orderService.findByDeliveryHeaderId(moDto.getDeliveryHeaderId());

        if (orderDto == null) {
            throw new RuntimeException(moDto.getDeliveryHeaderId() + "系统无此订单!");
        }

        if (!orderDto.getDeliveryStatus().equals("lm_initial")) {
            throw new RuntimeException(moDto.getLabelNo() + "标签背后的送货单" + orderDto.getBarcodeNumber() + "已取消(标签失效)!");
        }

        // 生成AGV任务和入库任务
        createTasks(item, stock, srcPoint, endPoint, moDto.getLabelNo(), moDto, orderDto);

        // 更新容器状态和目标点位状态
        updateStockAndEndPoint(stock,endPoint);


    }

    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, "RACK_MOVE_FULL");
        agvTaskService.create(agvTask);

        // 生成入库任务

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

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

        //生成收货记录
        Task task = new Task(item, itemKey, asnDetail.getOrderNumber(), 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);
    }

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