package com.cyksj.service.mange.stock.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cyksj.common.exception.BusinessRuntimeException;
import com.cyksj.common.snowflake.Sequence;
import com.cyksj.mapper.stock.*;
import com.cyksj.model.entity.*;
import com.cyksj.model.request.StockUpReq;
import com.cyksj.service.mange.stock.GoodsDonStockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author chan
 * @date 2022/12/7 5:55 PM
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GoodsDonStockServiceImpl implements GoodsDonStockService {

    private final GoodsDonStockMapper stockMapper;

    private final GoodsDonStockRecordMapper stockRecordMapper;

    private final OrderDonStockMapper orderDonStockMapper;

    private final GoodsSkuStockRelateMapper skuStockRelateMapper;

    private final GoodsSkuStockRelateChangeRecordMapper relateChangeRecordMapper;

    private static final Sequence SEQUENCE = new Sequence(0);

    private final List<String> ADD_OPERATE = List.of("put", "refund");

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void upStockRelate(Long stockId, Long orderId, String status) {
        if ("refund".equals(status)) {
            List<OrderDonStock> orderDonStocks = orderDonStockMapper.selectList(Wrappers.lambdaQuery(OrderDonStock.class).eq(OrderDonStock::getOrderId, orderId));

            //退款
            orderDonStocks.forEach((orderDonStock)->{
                orderDonStock.setStatus("refund");
                orderDonStockMapper.updateById(orderDonStock);
                GoodsDonStockRecord putRecord = stockRecordMapper.selectById(orderDonStock.getRecordId());
                //发货库存操作已撤销
                if (putRecord.getIsUndo()) {
                    return;
                }

                GoodsDonStock stock = stockMapper.selectById(putRecord.getStockId());
                //新增库存记录
                GoodsDonStockRecord record = new GoodsDonStockRecord();
                record.setNum(1);
                record.setStockId(putRecord.getStockId());
                record.setThenTotal(stock.getTotal());
                record.setType("refund");
                record.setPrice(putRecord.getPrice());
                stockRecordMapper.insert(record);

                //修改批次可用库存数
                putRecord.setAvailable(putRecord.getAvailable() + 1);
                stockRecordMapper.updateById(putRecord);
                //修改库存商品可用数
                stock.setTotal(stock.getTotal() + 1);
                stock.setStock(stock.getStock() + 1);
                stock.setUpgrade(stock.getUpgrade() + 1);
                stockMapper.updateById(stock);
            });
            //1.修改退款状态
            //2.退回库存

        }else {
            //发货
            GoodsDonStockRecord putRecord = stockRecordMapper.selectOne(Wrappers.lambdaQuery(GoodsDonStockRecord.class)
                    .eq(GoodsDonStockRecord::getStockId, stockId)
                    .eq(GoodsDonStockRecord::getType, "put")
                    .gt(GoodsDonStockRecord::getAvailable, 0)
                    .eq(GoodsDonStockRecord::getIsUndo, false)
                    .orderByAsc(GoodsDonStockRecord::getCreatedTime)
                    .last(" limit 1")
            );
            if (putRecord == null) {
                throw BusinessRuntimeException.getInstance("该库存商品不足.");
            }

            //储存发货库存信息
            OrderDonStock orderDonStock = new OrderDonStock();
            orderDonStock.setOrderId(orderId);
            orderDonStock.setRecordId(putRecord.getId());
            orderDonStock.setStatus(status);
            orderDonStockMapper.insert(orderDonStock);

            GoodsDonStock stock = stockMapper.selectById(putRecord.getStockId());
            //新增库存记录
            GoodsDonStockRecord record = new GoodsDonStockRecord();
            record.setNum(1);
            record.setStockId(stockId);
            record.setThenTotal(stock.getTotal());
            record.setType("transport");
            record.setPrice(putRecord.getPrice());
            stockRecordMapper.insert(record);

            //修改批次可用库存数
            putRecord.setAvailable(putRecord.getAvailable() - 1);
            stockRecordMapper.updateById(putRecord);
            //修改库存商品可用数
            stock.setTotal(stock.getTotal() - 1);
            stock.setStock(stock.getStock() - 1);
            stock.setUpgrade(stock.getUpgrade() - 1);
            stockMapper.updateById(stock);
        }
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void incr(StockUpReq stock) {
        GoodsDonStock goodsDonStock = stockMapper.selectById(stock.getId());

        //新增库存明细
        GoodsDonStockRecord record = new GoodsDonStockRecord();
        record.setVoucher(stock.getVoucher());
        record.setNum(stock.getNum());
        record.setPrice(stock.getPrice());
        record.setAvailable(stock.getNum());
        record.setStockId(stock.getId());
        record.setThenTotal(goodsDonStock.getTotal());
        record.setType("put");
        stockRecordMapper.insert(record);

        //增加总库存数,可用库存数
        goodsDonStock.setTotal(goodsDonStock.getTotal() + stock.getNum());
        goodsDonStock.setStock(goodsDonStock.getStock() + stock.getNum());
        stockMapper.updateById(goodsDonStock);

    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void sub(StockUpReq stock) {
        GoodsDonStock goodsDonStock = stockMapper.selectById(stock.getId());
        GoodsDonStockRecord putRecord = stockRecordMapper.selectOne(
                Wrappers.lambdaQuery(GoodsDonStockRecord.class)
                        .eq(GoodsDonStockRecord::getStockId, stock.getId())
                        .eq(GoodsDonStockRecord::getType, "put")
                        .gt(GoodsDonStockRecord::getAvailable, 0)
                        .eq(GoodsDonStockRecord::getIsUndo, false)
                        .orderByAsc(GoodsDonStockRecord::getId)
                        .last(" limit 1")
        );
        if(putRecord == null){
            throw BusinessRuntimeException.getInstance("没有库存>0的批次");
        }
        if(putRecord.getAvailable() - stock.getNum() < 0){
            throw BusinessRuntimeException.getInstance("该批次货物仅可扣减" + putRecord.getAvailable() + "数");
        }
        putRecord.setAvailable(putRecord.getAvailable() - stock.getNum());
        stockRecordMapper.updateById(putRecord);
        //扣减库存明细
        GoodsDonStockRecord  record = new GoodsDonStockRecord();
        record.setNum(stock.getNum());
        record.setPrice(putRecord.getPrice());
        record.setStockId(stock.getId());
        record.setThenTotal(goodsDonStock.getTotal());
        record.setType("out");
        record.setRemark(stock.getRemark());
        stockRecordMapper.insert(record);

        //增加总库存数,可用库存数
        goodsDonStock.setTotal(goodsDonStock.getTotal() - stock.getNum());
        goodsDonStock.setStock(goodsDonStock.getStock() - stock.getNum());
        stockMapper.updateById(goodsDonStock);

    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void upUnavailable(StockUpReq stock) {
        GoodsDonStock goodsDonStock = stockMapper.selectById(stock.getId());
        if (stock.getNum() > 0) {
            //增加
            if (goodsDonStock.getStock() <= stock.getNum()) {
                throw BusinessRuntimeException.getInstance("新增数量不可超过总库存数");
            }
            GoodsDonStockRecord putRecord = stockRecordMapper.selectOne(
                    Wrappers.lambdaQuery(GoodsDonStockRecord.class)
                            .eq(GoodsDonStockRecord::getStockId,stock.getId())
                            .eq(GoodsDonStockRecord::getType,"put")
                            .gt(GoodsDonStockRecord::getAvailable,0)
                            .orderByAsc(GoodsDonStockRecord::getStockId)
                            .last(" limit 1")
            );
            if(putRecord == null){
                throw BusinessRuntimeException.getInstance("没有库存>0的批次");
            }
            putRecord.setAvailable(putRecord.getAvailable() - stock.getNum());
            stockRecordMapper.updateById(putRecord);
            goodsDonStock.setUnavailable(goodsDonStock.getUnavailable() + Math.abs(stock.getNum()));
            goodsDonStock.setStock(goodsDonStock.getStock() - stock.getNum());
            stockMapper.updateById(goodsDonStock);
            //新增库存明细
            GoodsDonStockRecord  record = new GoodsDonStockRecord();
            record.setNum(stock.getNum());
            record.setPrice(stock.getPrice());
            record.setStockId(stock.getId());
            record.setThenTotal(goodsDonStock.getTotal());
            record.setType("out");
            record.setRemark(stock.getRemark());

        }else if(stock.getNum() < 0){
            //扣减
            if (goodsDonStock.getUnavailable() <= stock.getNum()) {
                throw BusinessRuntimeException.getInstance("扣减数量不可超过目前不可用数量");
            }

        }else {
            //清库

        }
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void upgrade(StockUpReq stock) {
        GoodsDonStock goodsDonStock = stockMapper.selectById(stock.getId());
        goodsDonStock.setUpgrade(goodsDonStock.getUpgrade() + stock.getNum());
        stockMapper.updateById(goodsDonStock);
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void save(GoodsDonStock stock) {
        stockMapper.insert(stock);
        GoodsDonStockRecord record = stock.getRecord();
        record.setStockId(stock.getId());
        record.setType("put");
        record.setAvailable(record.getNum());
        stockRecordMapper.insert(record);

        stock.getRelateList().forEach((relate)->{
            relate.setStockId(stock.getId());
            skuStockRelateMapper.insert(relate);
        });
    }

    @Override
    public void upRecord(GoodsDonStockRecord record) {
        stockRecordMapper.update(null,Wrappers.lambdaUpdate(GoodsDonStockRecord.class).eq(GoodsDonStockRecord::getId,record.getId()).set(GoodsDonStockRecord::getRemark,record.getRemark()));
    }

    @Override
    public void del(Long stockId) {
        stockMapper.deleteById(stockId);
        skuStockRelateMapper.delete(Wrappers.lambdaQuery(GoodsSkuStockRelate.class).eq(GoodsSkuStockRelate::getStockId,stockId));
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void updateBindGoods(GoodsDonStock stock) {
        GoodsDonStock dbStock = stockMapper.selectById(stock.getId());
        if (dbStock == null) {
            throw BusinessRuntimeException.getInstance("库存不存在");
        }
        if (StrUtil.isNotBlank(stock.getTitle())) {
            dbStock.setTitle(stock.getTitle());
            stockMapper.updateById(dbStock);
        }
        List<GoodsSkuStockRelate> dbStockRelateList = skuStockRelateMapper.selectList(Wrappers.lambdaQuery(GoodsSkuStockRelate.class)
                .eq(GoodsSkuStockRelate::getStockId, stock.getId()));

        Map<Long, List<GoodsSkuStockRelate>> dbSkuMap = dbStockRelateList.stream().collect(Collectors.groupingBy(GoodsSkuStockRelate::getSkuId));

        List<GoodsSkuStockRelate> relateList = stock.getRelateList();
        Map<Long, List<GoodsSkuStockRelate>> skuMap = relateList.stream().collect(Collectors.groupingBy(GoodsSkuStockRelate::getSkuId));

        List<GoodsSkuStockRelate> insertList = new ArrayList<>();
        List<GoodsSkuStockRelate> deleteList = new ArrayList<>();

        //目前的
        relateList.forEach(relate->{
            List<GoodsSkuStockRelate> stockRelates = dbSkuMap.get(relate.getSkuId());
            if (CollUtil.isEmpty(stockRelates)) {
                insertList.add(relate);
            }
        });

        dbStockRelateList.forEach(data -> {
            List<GoodsSkuStockRelate> stockRelates = skuMap.get(data.getSkuId());
            if (CollUtil.isEmpty(stockRelates)) {
                deleteList.add(data);
            }
        });

        Long uniformId = SEQUENCE.nextId();
        String operator = stock.getOperator();

        insertList.forEach(insert->{
            insert.setStockId(stock.getId());
            skuStockRelateMapper.insert(insert);

            saveChangeRelateRecord(insert, "insert", uniformId, operator);
        });

        List<Long> deleteRelateIds = new ArrayList<>();
        deleteList.forEach(delete->{
            saveChangeRelateRecord(delete, "delete", uniformId, operator);

            deleteRelateIds.add(delete.getId());
        });

        if (CollUtil.isNotEmpty(deleteRelateIds)) {
            skuStockRelateMapper.deleteBatchIds(deleteRelateIds);
        }
    }

    public void saveChangeRelateRecord(GoodsSkuStockRelate skuStockRelate, String type, Long uniformId, String operator) {
        GoodsSkuStockRelateChangeRecord changeRecord = new GoodsSkuStockRelateChangeRecord();
        BeanUtil.copyProperties(skuStockRelate, changeRecord);
        changeRecord.setType(type);
        changeRecord.setUniformId(uniformId);
        changeRecord.setOperator(operator);
        relateChangeRecordMapper.insert(changeRecord);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void undoChange(Long recordId) {
        GoodsDonStockRecord goodsDonStockRecord = stockRecordMapper.selectById(recordId);
        if (goodsDonStockRecord == null) {
            throw BusinessRuntimeException.getInstance("该库存变更记录不存在");
        }
        //撤销
        Long stockId = goodsDonStockRecord.getStockId();
        //目前可用
        Integer num = goodsDonStockRecord.getAvailable();
        String type = goodsDonStockRecord.getType();
        //扣减库存回滚操作 数量为正时 置为负数
        if (!ADD_OPERATE.contains(type)) {
            //回滚扣除操作时
            num = goodsDonStockRecord.getNum();
            if (num > 0) {
                num = -num;
            }
        }
        handleUndoChange(type, goodsDonStockRecord.getId(), stockId, num);
    }

    /**
     * @param stockRecordId 库存存储记录id
     * @param stockId       库存id
     * @param num           库存数量
     */
    public void handleUndoChange(String type, Long stockRecordId, Long stockId, Integer num) {
        GoodsDonStock goodsDonStock = stockMapper.selectById(stockId);
        if (ADD_OPERATE.contains(type) && goodsDonStock.getTotal() <= 0) {
            throw BusinessRuntimeException.getInstance("当前商品库存为0,不可撤销该增加库存操作");
        }
        int update = stockRecordMapper.update(null, Wrappers.lambdaUpdate(GoodsDonStockRecord.class)
                .set(GoodsDonStockRecord::getIsUndo, true)
                .set(num > 0, GoodsDonStockRecord::getAvailable, 0)
                .eq(GoodsDonStockRecord::getId, stockRecordId)
                .eq(GoodsDonStockRecord::getIsUndo, false));

        if (update > 0) {
            //回滚扣减库存操作
            if (num < 0) {
                String recordType = "put";
                Boolean isUndo = false;
                GoodsDonStockRecord record = stockRecordMapper.selectUndoRecord(stockId, isUndo, recordType);
                if (record == null) {
                    isUndo = true;
                    record = stockRecordMapper.selectUndoRecord(stockId, isUndo, recordType);
                }
                if (record != null) {
                    Integer available = record.getAvailable();
                    //回滚新增库存的时候的可用数
                    update = stockRecordMapper.update(null, Wrappers.lambdaUpdate(GoodsDonStockRecord.class)
                            .set(GoodsDonStockRecord::getAvailable, available - num)
                            .set(GoodsDonStockRecord::getIsUndo, false)
                            .eq(GoodsDonStockRecord::getId, record.getId())
                            .eq(GoodsDonStockRecord::getAvailable, available));
                    if (update == 0) {
                        throw BusinessRuntimeException.getInstance("系统繁忙，请重试...");
                    }
                }
            }

            //恢复对应储存的库存
            update = stockMapper.update(null, Wrappers.lambdaUpdate(GoodsDonStock.class)
                    .set(GoodsDonStock::getTotal, goodsDonStock.getTotal() - num)
                    .set(GoodsDonStock::getStock, goodsDonStock.getStock() - num)
                    .eq(GoodsDonStock::getId, stockId)
                    .eq(GoodsDonStock::getTotal, goodsDonStock.getTotal()));
            if (update == 0) {
                throw BusinessRuntimeException.getInstance("系统繁忙，请重试...");
            }
        }
    }
}
