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

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.sy.coinage.core.constants.BusinessEnum;
import com.sy.coinage.core.exception.RetException;
import com.sy.coinage.core.redis.RedisService;
import com.sy.coinage.core.util.DateUtils;
import com.sy.coinage.core.vo.CacheUserVO;
import com.sy.coinage.sys.model.Dept;
import com.sy.coinage.sys.model.Dict;
import com.sy.coinage.sys.service.IDeptService;
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.WorkshopEntryReq;
import com.sy.coinage.workshop.req.vo.SerialNumberVO;
import com.sy.coinage.workshop.service.*;
import com.sy.coinage.workshop.vo.ViewInfoVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

import java.text.ParseException;

/**
 * -车间入库单（仅记录入库单，及返检单）ServiceImpl
 */
@Service
public class WorkshopEntryServiceImpl extends ServiceImpl<WorkshopEntryDao, WorkshopEntry>
        implements IWorkshopEntryService {

    @Autowired
    private IBaseInfoService baseInfoService;

    @Autowired
    private IStockService stockService;

    @Autowired
    private IWorkshopEntryDetailService workshopEntryDetailService;

    @Autowired
    private IWorkshopAccountService workshopAccountService;

    @Autowired
    private IProductService productService;

    @Autowired
    private IUserService userService;

    @Autowired
    private RedisService redisService;

    @Autowired
    private IDeptService deptService;
    @Autowired
    private IDictService dictService;

    @Autowired
    private ILogisticsService logisticsService;

    @Autowired
    private IWorkshopLogService workshopLogService;

    @Override
    @Transactional
    public void add(WorkshopEntryReq req, CacheUserVO user) {
        Dept dept = this.deptService.getByCode(req.getWareId());

        // 如果没有品名 查部门最后一条
        if (req.getSecuritiesId() == null || req.getSecuritiesId() == 0) {
            BaseInfo info = baseInfoService.getLast(dept.getId());
            req.setSecuritiesId(info.getSecuritiesId());
        }
        // 根据品名ID获取产品信息，需要先给请求信息的品名ID赋予值
        Product product = productService.getById(req.getSecuritiesId());
        WorkshopEntry model = new WorkshopEntry();
        model.setSecuritiesId(req.getSecuritiesId());
        model.setSecurities(product.getSecurities());
        model.setCheckId(req.getCheckId());
        model.setChecker(this.userService.getById(req.getCheckId()).getRealName());
        model.setOperatorId(user.getId());
        model.setOperatorCn(user.getRealName());
        // 创建入库单
        model.setOrderNo(this.creadeOrderNo(product.getSecurities(), dept.getId()));
        model.setDeptId(dept.getId());
        model.setDept(dept.getName());
        // 部门和租户相同
        model.setRacketNum(req.getRacketNum());
//        // 拍子总枚数（拍子数量*每拍子箱子数量*每箱子枚数）
//        model.setRacketTotal(
//                req.getRacketNum() * product.getBoxAmount() * product.getAmountPerBox());
        if (req.getBoxNum() != null && req.getBoxNum() > 0) {
            model.setBoxNum(req.getBoxNum());
            model.setBoxTotal(req.getBoxNum() * product.getAmountPerBox());
        }
        if (req.getPiecesTotal() != null && req.getPiecesTotal() > 0) {
            model.setPiecesTotal(req.getPiecesTotal());
        }
        // 添加入库主表
        this.save(model);
        // 添加入库子表返回实际总箱数
        Integer racketTotal = this.addDetail(model, req, product, req.getWareId());
        // 修改总枚数
        model.setRacketTotal(racketTotal);
        this.updateById(model);
    }

    /**
     * 添加整拍
     *
     * @param serialNumber
     * @param rfid
     * @param model
     * @param product
     * @param wareId
     */
    private BaseInfo baseAdd(String serialNumber, String rfid, WorkshopEntry model, Product product,
                             Integer wareId) {
        BaseInfo info = null;
        WorkshopEntryDetail detail = new WorkshopEntryDetail();
        // 明细类型（每个拍子一条记录；零箱,零枚可能有一条记录） 1: 整拍 2: 零箱 3:零枚
        detail.setType(1);
        detail.setEntryId(model.getId());
        // 如果是整拍有以后数值、 零箱零枚没有
        info = this.baseInfoService.updateWorkShopStatus(serialNumber, rfid, 1, 2, wareId, 1,
                model.getDeptId(), model.getDept());
        detail.setRfid(info.getRfid());
        detail.setSerialNumber(info.getSerialNumber());
        detail.setTareWeight(info.getTareWeight());
        detail.setGrossWeight(info.getGrossWeight());
        detail.setWeightor(info.getWeightor());
        detail.setWeightorId(info.getWeightorId());
        detail.setWeightTime(info.getNewPrintTime());
        // 称重时间戳(yyyy-mm-dd hh24:mm:ss),封包线传递过来的称重打印时间
//        String d = DateUtils.toString(info.getWeightDate()) + " " + info.getWeightTime();
//        try {
//            detail.setWeightTime(DateUtils.toDate(d, DateUtils.YY_MM_DD_HH_mm_ss));
//        } catch (ParseException e) {
//            e.printStackTrace();
//            throw new RetException("称重时间格式化失败=" + d);
//        }
        // 将rfid对应的冠字号范围，拼装成字符串，保存在此字端，用于页面展示
//        detail.setCrownBetweenStr(info.getCrownPrefix() + info.getCrownFrom() + "-"
//            + info.getCrownPrefix() + info.getCrownTo());
        detail.setCrownBetweenStr(info.getCrownBetweenStr());
        // 容器数量（拍子就是1，零箱的就是多少箱）
        detail.setQty(1);
        // 临时库库位ID 多数据字典中取值 产成品库位 : 1 剔除品库位 : 2
        detail.setAreaId(1);
        // 车间内部状态：1.处于产成品库 2.处于剔除品库 3.上机台4.发往主库
        detail.setStatus(1);
        // 枚数总数 （每拍子箱子数量*每箱子枚数）
        detail.setQtyTotal(info.getQty() * product.getAmountPerBox());
        this.workshopEntryDetailService.save(detail);
        if (detail.getType().intValue() == 1) {
            this.sendInMsg(model, detail, info, wareId);
        }
        return info;
    }

    /**
     * 零箱零枚
     *
     * @param model
     * @param product
     * @param type
     * @param req
     * @return
     */
    private BaseInfo baseAddScattered(WorkshopEntry model, Product product, Integer type,
        WorkshopEntryReq req) {
        BaseInfo info = null;
        WorkshopEntryDetail detail = new WorkshopEntryDetail();
        // 明细类型（每个拍子一条记录；零箱,零枚可能有一条记录） 1: 整拍 2: 零箱 3:零枚
        detail.setType(type);
        detail.setEntryId(model.getId());
        // 如果是整拍有以后数值、 零箱零枚没有
        // 容器数量（拍子就是1，零箱的就是多少箱）
        if (type.intValue() == 2) {
            detail.setCrownBetweenStr(req.getCrownFrom() + "-" + req.getCrownTo());
            detail.setQty(req.getBoxNum());
            detail.setQtyTotal(detail.getQty() * product.getAmountPerBox());
        } else {
            detail.setQty(req.getPiecesTotal());
            detail.setQtyTotal(detail.getQty());
        }
        // 临时库库位ID 多数据字典中取值 产成品库位 : 1 剔除品库位 : 2
        detail.setAreaId(2);
        // 车间内部状态：1.处于产成品库 2.处于剔除品库 3.上机台4.发往主库
        detail.setStatus(2);
        this.workshopEntryDetailService.save(detail);
        return info;
    }

    private void sendInMsg(WorkshopEntry model, WorkshopEntryDetail detail, BaseInfo info,
                           Integer wareId) {
        ViewInfoVO vo = new ViewInfoVO();
        BeanUtils.copyProperties(detail, vo);
        vo.setStatus(1);
        vo.setInOrOut(2);
        vo.setOperateTime(model.getCreateTime());
        vo.setSecurities(model.getSecurities());
        vo.setChecker(model.getChecker());
        vo.setCreateBy(model.getOperatorCn());
        vo.setPrintTime(info.getNewPrintTime());
        vo.setDept(model.getDept());
        vo.setLocWare(info.getLocWare());
        vo.setLocWareId(info.getLocWareId());
        WebSocketServer.sendMessageClient(String.valueOf(wareId), vo);
    }

    /**
     * 添加入库子表
     *
     * @param model
     * @param req
     * @param product
     */
    private Integer addDetail(WorkshopEntry model, WorkshopEntryReq req, Product product, Integer wareId) {
        // 总枚数
        Integer racketTotal = 0;
        Integer areaId = BusinessEnum.PRODUCT_AREA.value();
        Dict dict = dictService.getByVal("shopWareOpt", wareId, null);
//        Integer wareId = Integer.parseInt(dict.getVal());
        // 录入自动拍数
        if (req.getAutoLs() != null && req.getAutoLs().size() > 0) {
            for (SerialNumberVO vo : req.getAutoLs()) {
                BaseInfo info = baseAdd(vo.getSerialNumber(), vo.getRfid(), model, product, wareId);
//                // 拆拍的跳过
//                if ((info.getUnpackageStatus() != null && info.getUnpackageStatus().intValue() == 2) ||
//                        info.getOriginType() == 2) {
//                    continue;
//                }
                racketTotal = racketTotal + (info.getQty() * product.getAmountPerBox());
                info.setStatus(2);
                this.baseInfoService.updateById(info);
//                String crownBetweenStr = info.getCrownPrefix() + info.getCrownFrom() + "-"
//                        + info.getCrownPrefix() + info.getCrownTo();
                // FIXME 记录物流信息日志表
                this.logisticsService.add(vo.getRfid(), vo.getSerialNumber(), wareId, dict.getName(), 2, model.getCheckId(), model.getChecker(),
                        model.getOperatorId(), model.getOperatorCn(), null, null);
                // 车间日志表
                this.workshopLogService.addWorkshopLog(info, info.getCrownBetweenStr(),
                        model.getSecuritiesId(), model.getSecurities(), vo.getRfid(),
                        vo.getSerialNumber(),
                        model.getDeptId(), model.getDept(),
                        model.getOperatorId(), model.getOperatorCn(),
                        model.getCheckId(), model.getChecker(), 3, 4, 1, null, null);
            }
        }
        // 录入手动拍数
        if (req.getManualLs() != null && req.getManualLs().size() > 0) {
            for (SerialNumberVO vo : req.getManualLs()) {
                BaseInfo info = baseAdd(vo.getSerialNumber(), null, model, product, wareId);
                // 拆拍的跳过
//                if ((info.getUnpackageStatus() != null && info.getUnpackageStatus().intValue() == 2) ||
//                        info.getOriginType() == 2) {
//                    continue;
//                }
                racketTotal = racketTotal + (info.getQty() * product.getAmountPerBox());
//                this.addLogistics(vo, model, req, baseInfo, wareId, dict.getName());
                // FIXME 记录物流信息日志表
                this.logisticsService.add(vo.getRfid(), vo.getSerialNumber(), wareId, dict.getName(), 2, model.getCheckId(), model.getChecker(),
                        model.getOperatorId(), model.getOperatorCn(), null, null);
                // 车间日志表
//                String crownBetweenStr = info.getCrownPrefix() + info.getCrownFrom() + "-"
//                        + info.getCrownPrefix() + info.getCrownTo();
                this.workshopLogService.addWorkshopLog(info, info.getCrownBetweenStr(),
                        model.getSecuritiesId(), model.getSecurities(), vo.getRfid(),
                        vo.getSerialNumber(),
                        model.getDeptId(), model.getDept(),
                        model.getOperatorId(), model.getOperatorCn(),
                        model.getCheckId(), model.getChecker(), 3, 4, 1, null, null);
            }
        }
        // 更新实时封箱成品库存 返回实时库存
        this.stockService.stockAdd(model.getSecuritiesId(), model.getSecurities(),
                areaId, wareId, dict.getName(), model.getRacketNum(), 0, 0, 0);
//        Integer wareTotal1 = WareUtil.piecesTotal(stock, product);
        Integer wareTotal1 = this.stockService.getProductStockTotal(req.getWareId(), req.getSecuritiesId(), product);
        // 车间 入成品库  2.封箱成品实物收发卡
        this.workshopAccountService.shopIn(1, model.getDeptId(), model.getDept(),
                model.getOperatorId(),
                model.getOperatorCn(), model.getCheckId(), model.getChecker(), model.getOrderNo(),
                racketTotal, wareTotal1, 2, 1, "机台", null,
                model.getSecuritiesId(), model.getSecurities());
        // FIXME 开始零箱零枚

        areaId = BusinessEnum.ELIMINATE_AREA.value();
        // 添加零箱
        if (req.getBoxNum() != null && req.getBoxNum() > 0) {
            baseAddScattered(model, product, 2, req);
            String crownBetweenStr = req.getCrownFrom() + "-" + req.getCrownTo();
            this.workshopLogService.addWorkshopLog(null, crownBetweenStr, model.getSecuritiesId(),
                    model.getSecurities(), null, null,
                    model.getDeptId(), model.getDept(),
                    model.getOperatorId(), model.getOperatorCn(),
                    model.getCheckId(), model.getChecker(), 3, 5, 2, req.getBoxNum(), null);
        }
        // 添加零枚
        if (req.getPiecesTotal() != null && req.getPiecesTotal() > 0) {
            baseAddScattered(model, product, 3, req);
            this.workshopLogService.addWorkshopLog(null, null, model.getSecuritiesId(),
                    model.getSecurities(), null, null,
                    model.getDeptId(), model.getDept(),
                    model.getOperatorId(), model.getOperatorCn(),
                    model.getCheckId(), model.getChecker(), 3, 5, 2, null, req.getPiecesTotal());
        }
        if (req.getBoxNum() != null && req.getBoxNum() > 0 || req.getPiecesTotal() != null && req.getPiecesTotal() > 0) {
            this.stockService.stockAdd(model.getSecuritiesId(),
                    model.getSecurities(), areaId, wareId, dict.getName(), 0, req.getBoxNum(),
                    req.getPiecesTotal(), 0);
            Integer eliminateStockTotal = this.stockService.getEliminateStockTotal(req.getWareId(), req.getSecuritiesId(), product);
            // 车间 入剔除品库 3.剔除品实物收发卡
            this.workshopAccountService.shopIn(1, model.getDeptId(), model.getDept(),
                    model.getOperatorId(), model.getOperatorCn(), model.getCheckId(),
                    model.getChecker(), model.getOrderNo(),
                    (model.getBoxTotal() == null ? 0 : model.getBoxTotal()) +
                            (model.getPiecesTotal() == null ? 0 : model.getPiecesTotal()), eliminateStockTotal, 3, 1,
                    "机台", null, model.getSecuritiesId(), model.getSecurities());
        }
        return racketTotal;
    }

    private String creadeOrderNo(String securities, Integer deptId) {
        // 车间出库单号由系统自动生成，编号由“品名+部门编号+T2+3位数字编号”构成，Y211-1T2001
        // 车间出库单号
        String resp = null;
        String key = "workshopentry_num0:" + deptId + ":" + securities;
        if (redisService.hasKey(key)) {
            resp = securities + "-" + deptId + "R2" + String.format("%05d",
                Integer.parseInt(this.redisService.get(key)) + 1);
            this.redisService.set(key,
                String.valueOf(Integer.parseInt(this.redisService.get(key)) + 1));
        } else {
            this.redisService.set(key, "0");
            resp = securities + "-" + deptId + "R2" + String.format("%05d", 1);
        }
        return resp;
    }

}
