package com.sy.coinage.workshop.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.sy.coinage.app.req.DeliveryUpdateReq;
import com.sy.coinage.app.req.DeliveryWareConfirmReq;
import com.sy.coinage.core.exception.RetException;
import com.sy.coinage.core.vo.CacheUserVO;
import com.sy.coinage.core.vo.OptVO;
import com.sy.coinage.sys.model.Dict;
import com.sy.coinage.sys.service.IDictService;
import com.sy.coinage.sys.service.IUserService;
import com.sy.coinage.websocket.WebSocketServer;
import com.sy.coinage.workshop.WareUtil;
import com.sy.coinage.workshop.req.vo.BackSerialNumberVO;
import com.sy.coinage.workshop.req.vo.SerialNumberVO;
import com.sy.coinage.workshop.service.*;
import com.sy.coinage.workshop.vo.ViewInfoVO;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sy.coinage.workshop.dao.DeliveryDao;
import com.sy.coinage.workshop.model.*;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * -发货单主表ServiceImpl
 */
@Service
public class DeliveryServiceImpl extends ServiceImpl<DeliveryDao, Delivery> implements IDeliveryService {

    @Autowired
    private IUserService userService;
    @Autowired
    private IBaseInfoService baseInfoService;
    @Autowired
    private IDeliveryDetailService deliveryDetailService;

    @Autowired
    private IStockService stockService;

    @Autowired
    private IDictService dictService;

    @Autowired
    private ILogisticsService logisticsService;

    @Autowired
    private IWorkshopAccountService workshopAccountService;

    @Autowired
    private IProductService productService;

    @Override
    @Transactional
    public void wareConfirm(DeliveryWareConfirmReq req, CacheUserVO user) {
        Date date = new Date();
        Delivery model = this.getByOrderNo(req.getOrderNo());
        if (model == null) {
            throw new RetException("发货单不存在，单号=" + req.getOrderNo());
        }
        Product product = productService.getById(model.getSecuritiesId());
        model.setOperatorId(user.getId());
        model.setOperator(user.getRealName());
        model.setCheckId(req.getCheckId());
        model.setDeliveryTime(date);
        model.setChecker(this.userService.getById(req.getCheckId()).getRealName());
        model.setUpdated(date);
        // 发货单状态  1:初始化 2 已发货
        model.setStatus(2);
        this.updateById(model);
        List<DeliveryDetail> list = new ArrayList<>();
        if (req.getAutoLs() != null && req.getAutoLs().size() > 0) {
            for (SerialNumberVO vo : req.getAutoLs()) {
                DeliveryDetail detail = this.baseDeliveryDetail(product, vo.getSerialNumber(), vo.getRfid(), model, date, 1);
                list.add(detail);
            }
        }
        if (req.getManualLs() != null && req.getManualLs().size() > 0) {
            for (SerialNumberVO vo : req.getManualLs()) {
                DeliveryDetail detail = this.baseDeliveryDetail(product, vo.getSerialNumber(), null, model, date, 2);
                list.add(detail);
            }
        }
        Map<Integer, Integer> map = new HashMap<>();
//        Integer totalBox = 0;// 箱数
        for (DeliveryDetail vo : list) {
//            totalBox = totalBox + vo.getQty();
            BaseInfo info = this.baseInfoService.getByRfid(vo.getRfid(), 12);
            if (map.containsKey(info.getLocWareId())) {
                Integer box = map.get(info.getLocWareId());
                map.put(info.getLocWareId(), box + info.getQty());
            } else {
                map.put(info.getLocWareId(), info.getQty());
            }
        }
        for (Entry<Integer, Integer> entry : map.entrySet()) {
            Integer wareId = entry.getKey();
            Integer totalBox = entry.getValue();
            Integer piecesTotal = totalBox * product.getAmountPerBox();
            List<Stock> stockList = this.stockService.getStockList(wareId, model.getSecuritiesId());
            Integer wareTotal = WareUtil.piecesTotal(stockList, product);
            // 1.实物收发卡-付出
            this.workshopAccountService.shopOut(1, null, null, model.getCreateId(),
                model.getCreateBy(),
                model.getCheckId(), model.getChecker(), model.getOrderNo(), piecesTotal, wareTotal,
                1,
                2, model.getAddressCn(), wareId, model.getSecuritiesId(),
                model.getSecurities());
        }

        // 箱数 * 枚数/箱
//        Integer piecesTotal = totalBox * product.getAmountPerBox();
//        List<Stock> stockList = this.stockService.getStockList(info.getLocWareId());
//        Integer wareTotal = WareUtil.piecesTotal(stockList, product);
//        // 1.实物收发卡-付出
//        this.workshopAccountService.shopOut(1, null, null, model.getCreateId(), model.getCreateBy(),
//            model.getCheckId(), model.getChecker(), model.getOrderNo(), piecesTotal, wareTotal, 1,
//            2, model.getAddressCn(), info.getLocWareId(), model.getSecuritiesId(),
//            model.getSecurities());

    }

    private DeliveryDetail baseDeliveryDetail(Product product, String serialNumber, String rfid, Delivery model, Date date, Integer regFlag) {
        BaseInfo info = null;
        if (StringUtils.isNotBlank(rfid)) {
            info = this.baseInfoService.getByRfid(rfid, 4);
        } else {
            info = this.baseInfoService.getBySerialNumberDesc(serialNumber, 4);
        }
        Dict dict = this.dictService.getByVal("wareOpt", info.getLocWareId(), null);
        info.setLocWare(dict.getName());
        DeliveryDetail detail = new DeliveryDetail();
        detail.setDeliveryId(model.getId());
        detail.setRfid(info.getRfid());
        detail.setRegFlag(regFlag);
        detail.setSerialNumber(info.getSerialNumber());
        // 生命周期状态:1初始登记 2:车间入库 3:车间出库 4:总库入库  5:主库抽检出库 6.车间抽检入库确认 7.车间抽检出库8 主库抽检返回确认 9返检总库出库 10:返检车间确认 11拆包 12：已发货 13:返回机台
//        BaseInfo info = this.baseInfoService.getByRfid(vo.getRfid(), 4);
        Integer oldStatus = info.getStatus();
        info.setStatus(12);
        info.setDeliveryTime(date);
        info.setAddressId(String.valueOf(model.getAddressId()));
        info.setAddressCn(model.getAddressCn());
        this.baseInfoService.updateById(info);
        detail.setWareId(info.getLocWareId());
//        detail.setCrownBetweenStr(info.getCrownPrefix() + info.getCrownFrom() + "-"
//                + info.getCrownPrefix() + info.getCrownTo());
        detail.setCrownBetweenStr(info.getCrownBetweenStr());
        detail.setTareWeight(info.getTareWeight());
        detail.setGrossWeight(info.getGrossWeight());
        detail.setWeightor(info.getWeightor());
        detail.setWeightorId(info.getWeightorId());
        detail.setDeliveryTime(date);
        detail.setPrintTime(info.getNewPrintTime());
        detail.setDelFlag(1);
        if (oldStatus.intValue() == 11 || (info.getUnpackageStatus() != null && info.getUnpackageStatus() == 2) ||
                info.getOriginType() == 2) {
            // 是否整拍 1:是整拍 2:是拆拍
            detail.setIsWhole(2);
            detail.setQty(info.getQty());
        } else {
            // 是否整拍 1:是整拍 2:是拆拍
            detail.setIsWhole(1);
            detail.setQty(product.getBoxAmount());
        }
        this.deliveryDetailService.save(detail);
        if (oldStatus.intValue() == 11 || (info.getUnpackageStatus() != null && info.getUnpackageStatus() == 2) ||
                info.getOriginType() == 2) {
            this.stockService.stockSub(model.getSecuritiesId(), model.getSecurities(), info.getLocAreaId(), info.getLocWareId(), dict.getName(), 0, info.getQty(), 0, 0);
        } else {
            this.stockService.stockSub(model.getSecuritiesId(), model.getSecurities(), info.getLocAreaId(), info.getLocWareId(), dict.getName(), 1, 0, 0, 0);
        }
        // FIXME 修改库存 如果是拆拍 或者 零箱数大于0 // 是否拆拍
        // 生命周期状态:1初始登记 2:车间入库 3:车间出库 4:总库入库 5:主库抽检出库 6.车间抽检入库确认
        // 7.车间抽检出库8 主库抽检返回确认 9返检总库出库 10:返检车间确认 11拆包 12：已发货 13:返回机台
        // FIXME 记录物流信息日志表
        this.logisticsService.add(detail.getRfid(), detail.getSerialNumber(), info.getLocWareId(), dict.getName(), info.getStatus(), model.getCheckId(), model.getChecker(),
                model.getOperatorId(), model.getOperator(), null, model.getAddressCn());
        this.sendOutMsg(model, detail, info);
        return detail;
        // 发送消息推送
    }

    private void sendOutMsg(Delivery model, DeliveryDetail detail, BaseInfo info) {
        ViewInfoVO vo = new ViewInfoVO();
        BeanUtils.copyProperties(detail, vo);
        vo.setInOrOut(3);
        vo.setStatus(5);
        vo.setLocWare(info.getLocWare());
        vo.setLocWareId(info.getLocWareId());
        vo.setOperateTime(detail.getDeliveryTime());
        vo.setSecurities(model.getSecurities());
        vo.setChecker(model.getChecker());
        vo.setCreateBy(model.getCreateBy());
        vo.setPrintTime(detail.getPrintTime());
        vo.setDept(info.getDept());
        WebSocketServer.sendMessageClient(String.valueOf(info.getLocWareId()), vo);

    }

    @Override
    @Transactional
    public void update(DeliveryUpdateReq req, CacheUserVO user) {
        Date date = new Date();
        Delivery model = this.getByOrderNo(req.getOrderNo());
        if (model == null) {
            throw new RetException("出库单不存在，单号=" + req.getOrderNo());
        }
        Product product = productService.getById(model.getSecuritiesId());
        // 删除原记录入库 更新状态
        for (BackSerialNumberVO vo : req.getDelList()) {
            DeliveryDetail detail = this.getByRfidSerialNumber(model.getId(), vo.getRfid(), vo.getSerialNumber());
            // 生命周期状态:1初始登记 2:车间入库 3:车间出库 4:总库入库  5:主库抽检出库 6.车间抽检入库确认 7.车间抽检出库8 主库抽检返回确认 9返检总库出库 10:返检车间确认 11拆包 12：已发货 13:返回机台
            Dict dict = this.dictService.getByVal("wareOpt", vo.getWareId(), null);
            BaseInfo info = this.baseInfoService.getByRfid(vo.getRfid(), 12);
            info.setAddressCn("");
            info.setAddressId("");
            info.setDeliveryTime(null);
            info.setLocWareId(vo.getWareId());
            info.setLocWare(dict.getName());
            info.setLocAreaId(vo.getAreaId());
            info.setStatus(4);
            this.baseInfoService.updateById(info);
            // 登记类型： 1: 扫描登记  2: 手动登记
            this.deliveryDetailService.removeById(detail.getId());
            // FIXME 修改库存 或者 零箱数大于0 // 是否拆拍
            if ((info.getUnpackageStatus() != null && info.getUnpackageStatus().intValue() == 2) ||
                    info.getOriginType() == 2) {
                this.stockService.stockAdd(model.getSecuritiesId(), model.getSecurities(), vo.getAreaId(), vo.getWareId(), dict.getName(), 0, info.getQty(), 0, 0);
            } else {
                this.stockService.stockAdd(model.getSecuritiesId(), model.getSecurities(), vo.getAreaId(), vo.getWareId(), dict.getName(), 1, 0, 0, 0);
            }
            // FIXME 记录物流信息日志表
            this.logisticsService.add(detail.getRfid(), detail.getSerialNumber(), info.getLocWareId(), dict.getName(), info.getStatus(), model.getCheckId(), model.getChecker(),
                    model.getOperatorId(), model.getOperator(), null, model.getAddressCn());
        }
        // 增加新记录出库
        for (SerialNumberVO vo : req.getAddList()) {
            this.baseDeliveryDetail(product, vo.getSerialNumber(), vo.getRfid(), model, date, 1);
        }
    }

    @Override
    @Transactional
    public void print(Integer id, CacheUserVO user) {
        LambdaUpdateWrapper<DeliveryDetail> updateWrapper = new LambdaUpdateWrapper<>();
        // 打印状态: 1.未打印 2.已打印
        updateWrapper.set(DeliveryDetail::getPrintTime, new Date());
        updateWrapper.eq(DeliveryDetail::getDeliveryId, id);
        this.deliveryDetailService.update(updateWrapper);

    }

    private DeliveryDetail getByRfidSerialNumber(Integer deliveryId, String rfid, String serialNumber) {
        LambdaQueryWrapper<DeliveryDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeliveryDetail::getDeliveryId, deliveryId);
        queryWrapper.eq(DeliveryDetail::getRfid, rfid);
        queryWrapper.eq(DeliveryDetail::getSerialNumber, serialNumber);
        return this.deliveryDetailService.getOne(queryWrapper);
    }

    private Delivery getByOrderNo(String orderNo) {
        LambdaQueryWrapper<Delivery> queryWrapper = new LambdaQueryWrapper<>();
        // 单号
        queryWrapper.eq(Delivery::getOrderNo, orderNo);
        return this.getOne(queryWrapper);
    }

}
