package com.fjhx.service.stock.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.Condition;
import com.fjhx.constants.StockJournalTypeConstant;
import com.fjhx.entity.stock.Stock;
import com.fjhx.entity.stock.StockJournal;
import com.fjhx.enums.stock.InTypeEnum;
import com.fjhx.enums.stock.OutTypeEnum;
import com.fjhx.mapper.stock.StockJournalMapper;
import com.fjhx.params.stock.StockChangeVo;
import com.fjhx.params.stock.StockJournalVo;
import com.fjhx.service.stock.StockJournalService;
import com.fjhx.service.stock.StockService;
import com.fjhx.uitl.code.CodeEnum;
import com.fjhx.utils.UserClientUtil;
import com.fjhx.utils.wrapperUtil.IWrapper;
import org.springblade.core.tool.utils.Func;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 出入库流水记录 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-11-24
 */
@Service
public class StockJournalServiceImpl extends ServiceImpl<StockJournalMapper, StockJournal> implements StockJournalService {

    @Lazy
    @Autowired
    private StockService stockService;

    @Override
    public Page<StockJournal> getPage(Map<String, String> condition) {

        IWrapper<StockJournal> wrapper = IWrapper.getWrapper(condition);
        wrapper.eq("t1", StockJournal::getWarehouseId)
                .eq("t1", StockJournal::getType)
                .eq("t1", StockJournal::getDetailsType)
                .ge("t1", StockJournal::getCreateTime, condition.get("startTime"))
                .le("t1", StockJournal::getCreateTime, condition.get("endTime"))
                .apply(Func.isNotEmpty(condition.get("logisticsInfoCode")), "instr(t3.logistics_info_code, '" + condition.get("logisticsInfoCode") + "') > 0")
                .orderByDesc("t1", StockJournal::getId);

        Page<StockJournal> page = baseMapper.getPage(createPage(condition), wrapper);
        if (Func.isNotEmpty(page.getRecords())) {
            //操作人名称map
            Map<Long, String> userNameMap = UserClientUtil.getUserNameMap(page.getRecords(), StockJournal::getCreateUser);

            for (StockJournal record : page.getRecords()) {
                if (Func.isNotEmpty(userNameMap) && Func.isNotEmpty(userNameMap.get(record.getCreateUser()))) {
                    record.setCreateName(userNameMap.get(record.getCreateUser()));
                }
            }
        }
        return page;
    }

    @Override
    public void add(StockJournalVo stockJournalVo) {
        save(stockJournalVo);
    }

    @Override
    public void edit(StockJournalVo stockJournalVo) {
        updateById(stockJournalVo);
    }

    @Override
    public void delete(StockJournalVo stockJournalVo) {
        removeById(stockJournalVo.getId());
    }

    /**
     * 添加流水记录
     *
     * @return
     */
    public List<StockJournal> addJournal(StockChangeVo stockChangeVo) {
        List<? extends StockChangeVo.ChangeDetails> changeDetailsList = stockChangeVo.getChangeDetailsList();
        Enum<?> typeEnum = stockChangeVo.getTypeEnum();

        // 添加入库明细
        List<StockJournal> stockJournalList = new ArrayList<>();

        synchronized (this) {

            String code = null;

            if (typeEnum instanceof InTypeEnum) {
                switch ((InTypeEnum) typeEnum) {
                    case PURCHASE:
                        code = CodeEnum.IN_PURCHASE.getCode();
                        break;
                    case MANUAL:
                        code = CodeEnum.IN_JOURNAL.getCode();
                        break;
                }
            } else {
                switch ((OutTypeEnum) typeEnum) {
                    case PICKING:
                    case SALE:
                    case RETURN_GOODS:
                    case SCRAP:
                        code = CodeEnum.OUT_JOURNAL.getCode();
                        break;
                    case PURCHASE:
                        code = CodeEnum.S_OUT_JOURNAL.getCode();
                        break;
                    case JD:
                        code = CodeEnum.JD_OUT_JOURNAL.getCode();
                }
            }

            for (StockChangeVo.ChangeDetails changeDetails : changeDetailsList) {

                // 变更数量
                BigDecimal changeQuantity = changeDetails.getChangeQuantity();
                // 变更数量小于等于0，则跳过
                if (changeQuantity.compareTo(BigDecimal.ZERO) <= 0) {
                    continue;
                }

                // 业务id
                Long businessId = ObjectUtil.defaultIfNull(changeDetails.getBusinessId(), stockChangeVo.getDefaultBusinessId());
                // 产品id
                Long goodsId = changeDetails.getGoodsId();
                // 仓库id
                Long warehouseId = ObjectUtil.defaultIfNull(changeDetails.getWarehouseId(), stockChangeVo.getDefaultWarehouseId());
                // 备注
                String remarks = ObjectUtil.defaultIfNull(changeDetails.getRemarks(), stockChangeVo.getDefaultRemarks());

                // 获取加权平均单价
                Stock stock = stockService.getOne(q -> q.eq(Stock::getWarehouseId, warehouseId).eq(Stock::getGoodsId, goodsId));
                BigDecimal weightingAveragePrice = BigDecimal.ZERO;
                if (stock != null) {
                    weightingAveragePrice = ObjectUtil.defaultIfNull(stock.getWeightingAveragePrice(), BigDecimal.ZERO);
                }

                StockJournal stockJournal = new StockJournal();
                if (typeEnum instanceof InTypeEnum) {
                    stockJournal.setType(StockJournalTypeConstant.IN);
                    stockJournal.setDetailsType(((InTypeEnum) typeEnum).getKey());
                    stockJournal.setActualQuantity(BigDecimal.ZERO);
                } else {
                    stockJournal.setType(StockJournalTypeConstant.OUT);
                    stockJournal.setDetailsType(((OutTypeEnum) typeEnum).getKey());
                }

                stockJournal.setAmount(weightingAveragePrice.multiply(changeQuantity));
                stockJournal.setCode(code);
                stockJournal.setBusinessId(businessId);
                stockJournal.setGoodsId(goodsId);
                stockJournal.setWarehouseId(warehouseId);
                stockJournal.setChangeQuantity(changeQuantity);
                stockJournal.setRemarks(remarks);
                stockJournalList.add(stockJournal);
            }

            saveBatch(stockJournalList);
        }
        return stockJournalList;
    }

    @Override
    public Page<Map<String, Object>> getManualOutPage(Condition condition) {

        IWrapper<Object> wrapper = IWrapper.getWrapper(condition)
                .eq("sj", StockJournal::getType, StockJournalTypeConstant.OUT)
                .like("sj", StockJournal::getCode)
                .func(q -> {
                    Integer type = condition.getInt("type");
                    if (ObjectUtil.isEmpty(type)) {
                        q.in("sj", StockJournal::getDetailsType, OutTypeEnum.getHandleOutList());
                    } else {
                        q.eq("sj", StockJournal::getDetailsType, type);
                    }
                })
                .eq("sj", StockJournal::getWarehouseId)
                .eq("sj", StockJournal::getCreateUser)
                .periodTime("sj", StockJournal::getCreateTime);

        Page<Map<String, Object>> manualOutPage = baseMapper.getManualOutPage(condition.getPage(), wrapper);
        List<Map<String, Object>> records = manualOutPage.getRecords();
        if (records.size() == 0) {
            return manualOutPage;
        }
        UserClientUtil.setUserName(records, "createUser", "createUserName");

        return manualOutPage;
    }

    /**
     * 手动入库列表
     *
     * @param condition 查询条件
     * @return
     */
    @Override
    public Page<StockJournal> getManualInStockPage(Condition condition) {
        IWrapper<StockJournal> wrapper = IWrapper.getWrapper(condition);
        wrapper.eq("t1", StockJournal::getType, StockJournalTypeConstant.IN)
                .eq("t1", StockJournal::getDetailsType, InTypeEnum.MANUAL.getKey())
                .eq("t1", StockJournal::getWarehouseId)
                .ge("t1", StockJournal::getCreateTime, condition.get("startTime"))
                .le("t1", StockJournal::getCreateTime, condition.get("endTime"))
                .and(Func.isNotEmpty(condition.get("keyword")), o -> o.apply("instr(t2.`code`, '" + condition.get("keyword") + "') > 0").or().apply("instr(t2.`name`, '" + condition.get("keyword") + "') > 0").or().apply("instr(t3.`name`, '" + condition.get("keyword") + "') > 0"))
                .orderByDesc("t1", StockJournal::getId);

        Page<StockJournal> page = baseMapper.getManualInStockPage(createPage(condition), wrapper);
        if (Func.isNotEmpty(page.getRecords())) {
            //操作人名称map
            Map<Long, String> userNameMap = UserClientUtil.getUserNameMap(page.getRecords(), StockJournal::getCreateUser);

            for (StockJournal record : page.getRecords()) {
                if (Func.isNotEmpty(userNameMap) && Func.isNotEmpty(userNameMap.get(record.getCreateUser()))) {
                    record.setCreateName(userNameMap.get(record.getCreateUser()));
                }
            }
        }
        return page;
    }

    // /**
    //  * 到货质检列表
    //  *
    //  * @param condition 查询条件
    //  * @return
    //  */
    // @Override
    // public Page<StockJournal> getArrivalQualityPage(Map<String, Object> condition) {
    //     IWrapper<StockJournal> wrapper = IWrapper.getWrapper(condition);
    //     wrapper.eq("t1", StockJournal::getType, StockJournalTypeConstant.IN)
    //             .eq("t1", StockJournal::getDetailsType, InTypeEnum.PURCHASE.getKey())
    //             .keyword(
    //                     new KeywordData("t3.`code`"),
    //                     new KeywordData("t4.`name`"),
    //                     new KeywordData("t5.`name`")
    //             )
    //             .groupBy("t1.`code`")
    //             .orderByDesc("t1", ApplyPurchase::getCode);
    //
    //     Page<StockJournal> page = baseMapper.getArrivalQualityPage(createPage(condition), wrapper);
    //     List<StockJournal> records = page.getRecords();
    //     if (records.size() == 0) {
    //         return page;
    //     }
    //
    //     Map<Long, String> userNameMap = UserClientUtil.getUserNameMap(records, BaseEntity::getCreateUser);
    //
    //     for (StockJournal record : records) {
    //         record.setCreateName(userNameMap.get(record.getCreateUser()));
    //     }
    //     return page;
    // }

    @Override
    public Page<Map<String, Object>> inOutDocument(Condition condition) {

        IWrapper<Object> wrapper = IWrapper.getWrapper(condition)
                .eq("sj", StockJournal::getType)
                .like("sj", StockJournal::getCode)
                .eq("sj", StockJournal::getCreateUser)
                .eq("sj", StockJournal::getWarehouseId)
                .periodTime("sj", StockJournal::getCreateTime)
                .groupBy("sj.code")
                .orderByDesc("sj", StockJournal::getId);

        Page<Map<String, Object>> page = baseMapper.inOutDocument(condition.getPage(), wrapper);

        UserClientUtil.setUserName(page.getRecords(),"createUser","createUserName");

        return page;
    }
}
