package com.fjhx.wms.service.stock.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.common.utils.Assert;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.wms.entity.arrival.po.ArrivalStockRecords;
import com.fjhx.wms.entity.arrival.po.ArrivalStockRecordsDetails;
import com.fjhx.wms.entity.stock.dto.StockWaitDetailsDto;
import com.fjhx.wms.entity.stock.dto.StockWaitDto;
import com.fjhx.wms.entity.stock.dto.StockWaitSelectDto;
import com.fjhx.wms.entity.stock.emums.JournalType;
import com.fjhx.wms.entity.stock.emums.StockWaitType;
import com.fjhx.wms.entity.stock.po.*;
import com.fjhx.wms.entity.stock.vo.StockWaitDetailsVo;
import com.fjhx.wms.entity.stock.vo.StockWaitVo;
import com.fjhx.wms.entity.warehouse.po.Warehouse;
import com.fjhx.wms.mapper.stock.StockWaitMapper;
import com.fjhx.wms.service.PurService;
import com.fjhx.wms.service.WmsService;
import com.fjhx.wms.service.arrival.ArrivalStockRecordsDetailsService;
import com.fjhx.wms.service.arrival.ArrivalStockRecordsService;
import com.fjhx.wms.service.stock.*;
import com.fjhx.wms.service.warehouse.WarehouseService;
import com.fjhx.wms.utils.CodeEnum;
import com.obs.services.internal.ServiceException;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.system.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p>
 * 待出入库 服务实现类
 * </p>
 *
 * @author
 * @since 2023-03-22
 */
@DS(SourceConstant.WMS)
@Service
public class StockWaitServiceImpl extends ServiceImpl<StockWaitMapper, StockWait> implements StockWaitService {
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private StockService stockService;
    @Autowired
    private StockJournalService stockJournalService;
    @Autowired
    private StockJournalDetailsService stockJournalDetailsService;
    @Autowired
    private StockWaitDetailsService stockWaitDetailsService;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private ArrivalStockRecordsService arrivalStockRecordsService;
    @Autowired
    private ArrivalStockRecordsDetailsService arrivalStockRecordsDetailsService;
    @Autowired
    private WmsService wmsService;
    @Autowired
    private StockFrozenService stockFrozenService;
    @Autowired
    private PurService purService;

    @Override
    public Page<StockWaitVo> getPage(StockWaitSelectDto dto) {
        IWrapper<StockWait> wrapper = getWrapper();
        //过滤入库/出库
        wrapper.eq(StockWait::getType, dto.getType());
        wrapper.eq("sw", StockWait::getBusinessType, dto.getBusinessType());
        wrapper.eq(StockWait::getBusinessCode, dto.getKeyword());
        wrapper.orderByDesc("sw", StockWait::getId);
        Page<StockWaitVo> page = this.baseMapper.getPage1(dto.getPage(), wrapper);

        List<StockWaitVo> records = page.getRecords();
        // 赋值产品属性
        productInfoService.attributeAssign(records, StockWaitVo::getProductId, (item, productInfo) -> {
            item.setProductCode(productInfo.getCode());
            item.setProductUnit(productInfo.getUnit());
            item.setProductType(productInfo.getType());
            item.setProductName(productInfo.getName());
            item.setProductSpec(productInfo.getSpec());
        });

        return page;
    }

    @Override
    public Page<StockWaitVo> getPageByWdly(StockWaitSelectDto dto) {
        IWrapper<StockWait> wrapper = getWrapper();
        wrapper.orderByDesc("sw", StockWait::getId);
        //过滤入库/出库
        wrapper.eq(StockWait::getType, dto.getType());
        wrapper.eq(StockWait::getBusinessCode, dto.getKeyword());
        wrapper.eq(StockWait::getStatus, dto.getStatus());
        wrapper.eq("sw", StockWait::getBusinessType, dto.getBusinessType());

        //过滤掉待出入库 已完成/手动结束 的数据
        wrapper.notIn("sw", StockWait::getStatus, 2, 3);

        Page<StockWaitVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);

        List<StockWaitVo> records = page.getRecords();
        //赋值操作人
        UserUtil.assignmentNickName(records, StockWaitVo::getCreateUser, StockWaitVo::setOperatorName);
        //赋值仓库名称和id
        List<Long> wids = new ArrayList<>();
        for (StockWaitVo stockWaitVo : records) {
            String victoriatouristJson = stockWaitVo.getVictoriatouristJson();
            if (ObjectUtil.isEmpty(victoriatouristJson)) {
                continue;
            }
            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            if (!json.containsKey("receiptWarehouseId")) {
                continue;
            }
            wids.add(json.getLong("receiptWarehouseId"));
        }
        if (ObjectUtil.isEmpty(wids)) {
            return page;
        }
        List<Warehouse> warehouses = warehouseService.listByIds(wids);
        Map<Long, String> warehousesMap = warehouses.stream().collect(Collectors.toMap(Warehouse::getId, Warehouse::getName));
        for (StockWaitVo stockWaitVo : records) {
            String victoriatouristJson = stockWaitVo.getVictoriatouristJson();
            if (ObjectUtil.isEmpty(victoriatouristJson)) {
                continue;
            }
            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            json.put("receiptWarehouseName", warehousesMap.get(json.getLong("receiptWarehouseId")));
            stockWaitVo.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        }

        return page;
    }

    @Override
    public StockWaitVo detail(Long id) {
        StockWait stockWait = this.getById(id);
        StockWaitVo result = BeanUtil.toBean(stockWait, StockWaitVo.class);

        StockWaitDetails stockWaitDetails = stockWaitDetailsService.getOne(q -> q.eq(StockWaitDetails::getStockWaitId, id));
        ProductInfo byId = productInfoService.getById(stockWaitDetails.getProductId());
        result.setProductName(byId.getName());
        result.setQuantity(stockWaitDetails.getQuantity());
        result.setStockWaitDetailsId(stockWaitDetails.getId());

        //获取明细列表
        List<StockWaitDetails> stockWaitDetailsList = stockWaitDetailsService.list(q -> q.eq(StockWaitDetails::getStockWaitId, id));
        List<StockWaitDetailsVo> stockWaitDetailsVos = BeanUtil.copyToList(stockWaitDetailsList, StockWaitDetailsVo.class);
        //赋值产品信息
        productInfoService.attributeAssign(stockWaitDetailsVos, StockWaitDetailsVo::getProductId, (item, productInfo) -> {
            item.setProductName(productInfo.getName());
        });
        result.setStockWaitDetailsList(stockWaitDetailsVos);

        return result;
    }

    @Override
    public StockWaitVo detailByWdly(Long id) {
        StockWait stockWait = this.getById(id);
        StockWaitVo result = BeanUtil.toBean(stockWait, StockWaitVo.class);
        List<StockWaitDetails> list = stockWaitDetailsService.list(q -> q.eq(StockWaitDetails::getStockWaitId, id));
        List<StockWaitDetailsVo> stockWaitDetailsVos = BeanUtil.copyToList(list, StockWaitDetailsVo.class);
        //根据业务id(到货id)查询采购单明细信息


        //赋值物品信息和采购信息
        List<Long> pids = stockWaitDetailsVos.stream().map(StockWaitDetails::getProductId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(pids)) {
            List<ProductInfo> productInfos = productInfoService.listByIds(pids);
            Map<Long, ProductInfo> productInfoMap = productInfos.stream().collect(Collectors.toMap(ProductInfo::getId, Function.identity()));
            for (StockWaitDetailsVo stockWaitDetails : stockWaitDetailsVos) {
                ProductInfo productInfo = productInfoMap.get(stockWaitDetails.getProductId());
                if (ObjectUtil.isEmpty(productInfo)) {
                    continue;
                }
                stockWaitDetails.setProductName(productInfo.getName());
                stockWaitDetails.setProductCode(productInfo.getCode());
                stockWaitDetails.setProductCustomCode(productInfo.getCustomCode());
            }
        }
        result.setStockWaitDetailsList(stockWaitDetailsVos);
        //如果是采购退货 赋值采购退货信息
        if (result.getBusinessType() == 4) {
            Object purchaseBackInfo = wmsService.getPurchaseBackInfo(result.getBusinessId());
            result.setPurchaseBackInfo(purchaseBackInfo);
        }
        return result;
    }

    @DSTransactional
    @Override
    public void add(StockWaitDetailsDto stockWaitDetailsDto) {
        stockWaitDetailsService.add(stockWaitDetailsDto);
    }

    @DSTransactional
    @Override
    public void addByWdly(StockWaitDto stockWaitDto) {
        List<Stock> stockList = new ArrayList<>();

        List<StockWaitDetails> stockWaitDetailsDtoList = stockWaitDto.getStockWaitDetailsList();
//        List<Long> dids = stockWaitDetailsDtoList.stream().map(StockWaitDetails::getId).collect(Collectors.toList());
        Map<Long, StockWaitDetails> stockWaitDetailsMap = stockWaitDetailsDtoList.stream().collect(Collectors.toMap(StockWaitDetails::getId, Function.identity()));
//        List<StockWaitDetails> stockWaitDetailss = stockWaitDetailsService.listByIds(dids);

        //已经完全入库数量统计
//        int statusFlag = 0;
//        for (StockWaitDetails stockWaitDetail : stockWaitDetailss) {
//            StockWaitDetails temp = stockWaitDetailsMap.get(stockWaitDetail.getId());
//            //更新已入库数量
//            BigDecimal receiptQuantity = stockWaitDetail.getReceiptQuantity() == null ? BigDecimal.ZERO : stockWaitDetail.getReceiptQuantity();
//            stockWaitDetail.setReceiptQuantity(receiptQuantity.add(temp.getQuantity()));
//
//            //计算已经完全入库的数量
//            if (stockWaitDetail.getReceiptQuantity().compareTo(stockWaitDetail.getQuantity()) >= 0) {
//                statusFlag++;
//            }
//        }
//        stockWaitDetailsService.updateBatchById(stockWaitDetailss);
//        //修改待入库状态
//        StockWait stockWait = getById(stockWaitDto.getId());
//        if (statusFlag == stockWaitDetailss.size()) {
//            stockWait.setStatus(2);//入库完成
//        } else {
//            stockWait.setStatus(1);//部分入库
//        }

        //更新已出入库数量以及待出入库状态
        stockWaitDetailsService.changeStockWaitStatus(stockWaitDto);
        StockWait stockWait = getById(stockWaitDto.getId());


        String victoriatouristJson = stockWait.getVictoriatouristJson();
        JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
        json.put("receiptWarehouseId", stockWaitDto.getWarehouseId());
        stockWait.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        updateById(stockWait);

        //操作库存
        List<Long> swdIds = stockWaitDetailsDtoList.stream().map(StockWaitDetails::getId).collect(Collectors.toList());
        Map<Long, StockWaitDetails> oldStockWaitDetailsMap = stockWaitDetailsService.mapKEntity(StockWaitDetails::getId, q -> q.in(StockWaitDetails::getId, swdIds));
        for (StockWaitDetails waitDetails : stockWaitDetailsDtoList) {
            StockWaitDetails temp = oldStockWaitDetailsMap.get(waitDetails.getId());
            Stock stock = new Stock();
            stock.setQuantity(waitDetails.getQuantity());
            stock.setProductId(temp.getProductId());
            stockList.add(stock);
        }
        //创建出入库记录
        Integer businessType = stockWait.getBusinessType();
        StockJournal stockJournal = new StockJournal();
        stockJournal.setOpType(stockWaitDto.getType());
        stockJournal.setType(getStockJournalType(businessType));
        stockJournal.setCode(stockWait.getType() == 1 ? CodeEnum.SIN_CODE.getCode() : CodeEnum.SOUT_CODE.getCode());
        stockJournal.setWarehouseId(stockWaitDto.getWarehouseId());
        stockJournal.setBusinessId(stockWaitDto.getId());
        stockJournal.setLinkCode(stockWait.getBusinessCode());
        //保存出入库记录
        stockJournalService.save(stockJournal);

        List<StockJournalDetails> stockJournalDetailsList = stockService.ModifyInventory(stockJournal.getId(), 3, stockList, stockWaitDto.getWarehouseId());
        //保存出入库明细
        stockJournalDetailsService.saveBatch(stockJournalDetailsList);

        //如果是采购到货 创建待质检记录
        if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType().equals(businessType)) {
            //创建采购到货入库记录
            ArrivalStockRecords arrivalStockRecords = new ArrivalStockRecords();
            arrivalStockRecords.setStockWaitId(stockWait.getId());
            arrivalStockRecords.setWarehouseId(stockWaitDto.getWarehouseId());
            arrivalStockRecords.setQualityStatus(0);
            arrivalStockRecords.setArrivalCode(json.getString("arrivalCode"));//设置到货编码
            arrivalStockRecordsService.save(arrivalStockRecords);
            //创建入库明细
            List<ArrivalStockRecordsDetails> arrivalStockRecordsDetailsList = new ArrayList<>();
            for (StockWaitDetails waitDetails : stockWaitDetailsDtoList) {
                ArrivalStockRecordsDetails arrivalStockRecordsDetails = new ArrivalStockRecordsDetails();
                arrivalStockRecordsDetails.setArrivalStockRecordsId(arrivalStockRecords.getId());
                arrivalStockRecordsDetails.setProductInfoId(waitDetails.getProductId());
                arrivalStockRecordsDetails.setQuantity(waitDetails.getQuantity());
                arrivalStockRecordsDetails.setQualityQuantity(BigDecimal.ZERO);
                arrivalStockRecordsDetailsList.add(arrivalStockRecordsDetails);
            }
            arrivalStockRecordsDetailsService.saveBatch(arrivalStockRecordsDetailsList);
        }
        //如果是采购到货修改到货状态
        if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType().equals(businessType)) {
            purService.updatePurchaseArrivalStatus(stockWait.getBusinessId());
        }

        //销售订单出库
        if (StockWaitType.SALE_ORDER_OUT.getDetailType().equals(businessType)) {
            wmsService.outbounds(stockWaitDto);
        }

        //生产任务待出库
        if (StockWaitType.PRODUCTION_TASK_OUT.getDetailType().equals(businessType)) {
            for (StockWaitDetails stockWaitDetailsDto : stockWaitDetailsDtoList) {
                StockWaitDetails stockWaitDetails = stockWaitDetailsMap.get(stockWaitDetailsDto.getId());
                //减少冻结库存
                StockFrozen stockFrozen = stockFrozenService.getOne(q -> q.eq(StockFrozen::getProductId, stockWaitDetails.getProductId()));
                BigDecimal subtract = stockFrozen.getFrozenQuantity().subtract(stockWaitDetailsDto.getQuantity());
                stockFrozen.setFrozenQuantity(subtract);
                stockFrozenService.updateById(stockFrozen);
            }
        }
    }

    @Override
    public void edit(StockWaitDto stockWaitDto) {
        this.updateById(stockWaitDto);
    }

    @Override
    public void delete(Long id) {
        this.removeById(id);
    }

    /**
     * 根据待出入库业务类型获取对应的出入库记录类型
     */
    @Override
    public Integer getStockJournalType(int businessType) {
        if (StockWaitType.BORDER_OF_LINE_IN.getDetailType().equals(businessType)) {
            //线边回仓库
            return JournalType.BORDER_OF_LINE_IN.getDetailType();
        } else if (StockWaitType.COMPLETION_IN.getDetailType().equals(businessType)) {
            //完工入库
            return JournalType.COMPLETION_IN.getDetailType();
        } else if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType().equals(businessType)) {
            //采购到货
            return JournalType.PURCHASE_ARRIVAL_IN.getDetailType();
        } else if (StockWaitType.BACK_OUT.getDetailType().equals(businessType)) {
            //退货出货
            return JournalType.BACK_OUT.getDetailType();
        } else if (StockWaitType.SALE_ORDER_OUT.getDetailType().equals(businessType)) {
            //销售订单出库
            return JournalType.SALES_OUT.getDetailType();
        } else if (StockWaitType.PRODUCTION_TASK_OUT.getDetailType().equals(businessType)) {
            //生产任务待出库
            return JournalType.PRODUCTION_TASK_OUT.getDetailType();
        } else {
            throw new ServiceException("未知待出入库业务类型");
        }
    }

    /**
     * 结束入库
     */
    @DSTransactional
    @Override
    public void endInStock(Long id) {
        StockWait stockWait = getById(id);
        Assert.notEmpty(stockWait, "无法查询到待入库信息");
        stockWait.setStatus(3);//设置状态为结束
        updateById(stockWait);
        wmsService.addEndInStockAbnormal(stockWait.getId(), stockWait.getBusinessCode());
    }

}
