package com.shkj.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import cn.hutool.extra.qrcode.QrConfig;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.shkj.common.core.domain.Result;
import com.shkj.common.core.redis.RedisCache;
import com.shkj.common.enums.IsDelEnum;
import com.shkj.common.utils.DateUtils;
import com.shkj.common.utils.SecurityUtils;
import com.shkj.common.utils.StringUtils;
import com.shkj.wms.bo.*;
import com.shkj.wms.constants.RedisLockConstants;
import com.shkj.wms.domain.BaseMold;
import com.shkj.wms.domain.BaseMoldBarcode;
import com.shkj.wms.domain.BusinOutInPlan;
import com.shkj.wms.domain.SysStockDetail;
import com.shkj.wms.enums.DeleteFlagEnum;
import com.shkj.wms.enums.PlanStatusEnum;
import com.shkj.wms.enums.PlanTypeEnum;
import com.shkj.wms.mapper.BaseMoldMapper;
import com.shkj.wms.service.IBaseMoldBarcodeService;
import com.shkj.wms.service.IBaseMoldService;
import com.shkj.wms.service.IBusinOutInPlanService;
import com.shkj.wms.service.ISysStockDetailService;
import com.shkj.wms.utils.IntIdUtil;
import com.shkj.wms.vo.BaseMoldVo;
import io.reactivex.rxjava3.core.Maybe;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 磨具Service业务层处理
 *
 * @author lch
 * @date 2023-06-01
 */
@Slf4j
@Service
public class BaseMoldServiceImpl extends ServiceImpl<BaseMoldMapper, BaseMold> implements IBaseMoldService {


    @Autowired
    private IBaseMoldBarcodeService baseMoldBarcodeService;
    @Autowired
    private ISysStockDetailService sysStockDetailService;

    @Autowired
    private IBusinOutInPlanService iBusinOutInPlanService;
    @Autowired
    RedisCache redisCache ;

    @Override
    public Result<BaseMoldVo> queryById(Long id) {
        BaseMold db = this.baseMapper.selectById(id);
        BaseMoldVo vo = BeanUtil.toBean(db, BaseMoldVo.class);
        return Result.ok().data(vo);
    }

    @Override
    public List<BaseMoldVo> queryList(BaseMoldQueryBo bo) {
        LambdaQueryWrapper<BaseMold> lqw = Wrappers.lambdaQuery();
        if (StrUtil.isNotBlank(bo.getMoldNo())) {
            lqw.and(w -> w.like(BaseMold::getMoldNo, bo.getMoldNo()).or().like(BaseMold::getMoldName, bo.getMoldNo()));
        }

        if (StrUtil.isNotBlank(bo.getMoldName())) {
            lqw.and(w -> w.like(BaseMold::getMoldNo, bo.getMoldName()).or().like(BaseMold::getMoldName, bo.getMoldName()));
        }
        lqw.eq(StrUtil.isNotBlank(bo.getType()), BaseMold::getType, bo.getType());
        lqw.eq(StrUtil.isNotBlank(bo.getModel()), BaseMold::getModel, bo.getModel());
        lqw.eq(StrUtil.isNotBlank(bo.getIsActivity()), BaseMold::getIsActivity, bo.getIsActivity());
        lqw.eq(BaseMold::getIsDel, IsDelEnum.NORMAL.getValue());
        lqw.orderByDesc(BaseMold::getCreateTime);
        List<BaseMoldVo> voList = entity2Vo(this.list(lqw));
        for (BaseMoldVo baseMoldVo : voList) {
            //根据模具在系统的创建时间，计算已使用时长（月）
            Date createTime = baseMoldVo.getCreateTime();
            Date currDate = DateUtils.getNowDate();
            int monthsBetween = DateUtils.getMonthsBetween(createTime, currDate);
            baseMoldVo.setUseDate(monthsBetween);
        }
        return voList;

    }

    /**
     * 实体类转化成视图对象
     *
     * @param collection 实体类集合
     * @return
     */
    private List<BaseMoldVo> entity2Vo(Collection<BaseMold> collection) {
        List<BaseMoldVo> voList = collection.stream()
                .map(any -> BeanUtil.toBean(any, BaseMoldVo.class))
                .collect(Collectors.toList());
        if (collection instanceof Page) {
            Page<BaseMold> page = (Page<BaseMold>) collection;
            Page<BaseMoldVo> pageVo = new Page<>();
            BeanUtil.copyProperties(page, pageVo);
            pageVo.addAll(voList);
            voList = pageVo;
        }
        return voList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> insertByAddBo(BaseMoldAddBo bo) {
        bo.setId(null);
        BaseMold add = BeanUtil.toBean(bo, BaseMold.class);
        add.setBarCode(IntIdUtil.generateIntId().toString());
        add.setIsDel(DeleteFlagEnum.NORMAL.getValue());
        add.setBranchId(SecurityUtils.getCurrentBranchId());
        Result result = checkEntity(add);
        if (!Result.isOk(result)) {
            return Result.err().msg(result.getMsg());
        }
        this.save(add);
        return Result.ok();
    }

    /**
     * 校验数据 (相同工号、相同作业类型、作业顺序不允许重复)
     *
     * @param entity
     * @return
     */
    private Result checkEntity(BaseMold entity) {
        Long id = entity.getId() != null ? entity.getId() : -1L;
        LambdaQueryWrapper<BaseMold> wrapper = new LambdaQueryWrapper<BaseMold>()
                .eq(BaseMold::getMoldNo, entity.getMoldNo())
                .eq(BaseMold::getModel,entity.getModel())
                .eq(BaseMold::getMoldName,entity.getMoldName())
                .eq(BaseMold::getIsDel, IsDelEnum.NORMAL.getValue());
        BaseMold one = getOne(wrapper);
        if (one != null && !id.equals(one.getId())) {
            log.info("存在重复数据：" + entity.getMoldNo());
            return Result.err().msg("存在重复数据");
        }
        return Result.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> updateByEditBo(BaseMoldAddBo bo) {
        BaseMold one = getById(bo.getId());
        if (one == null) {
            return Result.err().msg("不存在");
        }

        BaseMold update = BeanUtil.toBean(bo, BaseMold.class);
        update.setBranchId(SecurityUtils.getCurrentBranchId());
        update.setBarCode(one.getBarCode());
        Result result = checkEntity(update);
        if (!Result.isOk(result)) {
            return Result.err().msg(result.getMsg());
        }
        this.updateById(update);
        return Result.ok();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> deleteWithValidById(List<Long> ids, Boolean isValid) {
        BaseMold del = new BaseMold();
        del.setIsDel(IsDelEnum.DELETED.getValue());
        LambdaQueryWrapper<BaseMold> wrapper = new LambdaQueryWrapper<BaseMold>().in(BaseMold::getId, ids);
        List<BaseMold> baseMolds = this.list(wrapper);
        BaseMold baseMold = baseMolds.get(0);
        //查找系统是否有库存，有则不允许删除

        LambdaQueryWrapper<SysStockDetail> sysWrapper = new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getMoldId,baseMold.getId()
        ).last("limit 1");
        SysStockDetail sysStockDetail = sysStockDetailService.getOne(sysWrapper);
        if (sysStockDetail!=null){
            return Result.err().msg("此模具在库，不允许删除："+baseMold.getMoldNo());
        }

        this.update(del, wrapper);
        return Result.ok();
    }

    /**
     * 开关状态
     *
     * @param id     id
     * @param status 状态
     * @return {@code Result<Boolean>}
     */
    @Override
    public Result<Boolean> switchStatus(Long id, String status) {
        BaseMold mold = new BaseMold();
        mold.setId(id).setIsActivity(status);
        return this.updateById(mold) ? Result.ok() : Result.err();
    }

    /**
     * 打印条码
     *
     * @param id id
     * @return {@code Result<Boolean>}
     */
    @Override
    public Result<String> printBarcode(Long id) {
        BaseMold mold = getById(id);
        if (mold == null){
            return Result.err().msg("模具不存在");
        }
/*
        BaseMoldBarcodeAddBo bo = new BaseMoldBarcodeAddBo();
        bo.setMoldId(id).setMoldNo(mold.getMoldNo());
        Result<BaseMoldBarcode> result = baseMoldBarcodeService.addMoldBarcode(bo);
       if (!Result.isOk(result)){
           return Result.err().msg(result.getMsg());
       }

        BaseMoldBarcode data = result.getData();*/
        return Result.ok().data(mold.getBarCode());
    }

    /**
     * 根据模具条码查询模具信息
     *
     * @param bo 薄
     * @return {@code Result<List<BaseMoldVo>>}
     */
    @Override
    public Result<List<BaseMoldVo>> queryMoldByBarCode(BaseMoldBarcodeQueryBo bo) {

        Collection<String> keys = redisCache.keys(RedisLockConstants.containerCode+"*");
        if (CollectionUtils.isNotEmpty(keys)){
            for (String key : keys) {
                List<SysStockDetail> sysStockDetailList = redisCache.getCacheList(key);
                List<SysStockDetail> newStockDetailList = sysStockDetailList.stream().filter(x -> x.getQty().add(x.getInQty()).add(x.getOutQty()).compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
                for (SysStockDetail sysStockDetail : newStockDetailList) {
                    String barcode = sysStockDetail.getBarcode();
                    if (bo.getMoldBarcode().equals(barcode)){
                        return Result.err().msg("此模具在其他托盘尚未完成流程，不可入库此托盘");
                    }
                }
            }
        }


        String containerCode = bo.getContainerCode();
        if(StringUtils.isNotEmpty(containerCode)){
            List<SysStockDetail> sysStockDetailList = redisCache.getCacheList(RedisLockConstants.containerCode + "_" + containerCode);
            if (CollectionUtils.isNotEmpty(sysStockDetailList)) {
                List<SysStockDetail> collect = sysStockDetailList.stream().filter(x -> x.getBarcode().equals(bo.getMoldBarcode()))
                        .filter(x ->x.getQty().compareTo(BigDecimal.ZERO)>0).collect(Collectors.toList());
                //filter(x -> x.getQty().compareTo(BigDecimal.ZERO) > 0)
                if (collect.size()>0){
                    return Result.err().msg("此模具未出库，不需要扫描"+collect.get(0).getMoldNo());
                }
            }
        }

        //验证模具信息是否在库
        LambdaQueryWrapper<SysStockDetail> wrapper = new LambdaQueryWrapper<SysStockDetail>()
                .in(SysStockDetail::getBarcode, bo.getMoldBarcode());
        SysStockDetail one = sysStockDetailService.getOne(wrapper);
        if (one !=null){
            return  Result.err().msg("此模具在库内请确认");
        }

        List<BaseMoldVo> list = this.baseMapper.queryMoldByBarCode(bo);
        return Result.ok().data(list);
    }

    @Override
    public Result<List<BaseMoldVo>> queryMoldByContainerCode(BaseMoldBarcodeQueryBo bo) {
        String containerCode = bo.getContainerCode();

        LambdaQueryWrapper<BusinOutInPlan> eq = new LambdaQueryWrapper<BusinOutInPlan>()
                .eq(BusinOutInPlan::getContainerCode, containerCode)
                .notIn(BusinOutInPlan::getPlanStatus, PlanStatusEnum.FINISH.getValue(),PlanStatusEnum.CANCEL.getValue())
                .eq(BusinOutInPlan::getType, PlanTypeEnum.OUT.getValue());
        List<BusinOutInPlan> list =iBusinOutInPlanService.list(eq);
        if (CollectionUtils.isNotEmpty(list)) {
            log.info("存在对应的任务没有拣货完成 {}",list);
            return Result.err().msg("存在对应的任务没有拣货完成");
        }

        List<BaseMoldVo> moldVoList =null;
        if(StringUtils.isNotEmpty(containerCode)){
            List<SysStockDetail> sysStockDetailList = redisCache.getCacheList(RedisLockConstants.containerCode + "_" + containerCode);
            if (CollectionUtils.isNotEmpty(sysStockDetailList)) {
                List<SysStockDetail> collect = sysStockDetailList.stream().filter(x -> x.getQty().compareTo(BigDecimal.ZERO) > 0).collect(Collectors.toList());
                List<String> moldBarcodeList = new ArrayList<>();
                for (SysStockDetail sysStockDetail : collect) {
                    moldBarcodeList.add(sysStockDetail.getBarcode());
                }
                bo.setLstMoldBar(moldBarcodeList);
                if (moldBarcodeList.size()>0){
                    moldVoList = this.baseMapper.queryMoldByBarCode(bo);
                }
                if(moldVoList !=null && moldVoList.size()>0){
                    for (BaseMoldVo baseMoldVo : moldVoList) {
                        baseMoldVo.setIsOut("out");
                    }
                }
            }
        }
        return Result.ok().data(moldVoList);
    }


    @Override
    public Result<List<BaseMoldVo>> queryStockMoldByBarCode(BaseMoldBarcodeQueryBo bo) {
        List<BaseMoldVo> list = this.baseMapper.queryStockMoldByBarCode(bo);
        return Result.ok().data(list);
    }

    @Override
    public List<BaseMoldVo> queryStockMoldByBarCodePc(BaseMoldBarcodeQueryPageBo bo) {
        return this.baseMapper.queryStockMoldByBarCodePage(bo);
    }


    @Override
    public List<BaseMold> queryByMoldBarcodeList(List<String> moldBarcodeList) {
        LambdaQueryWrapper<BaseMold> wrapper = new LambdaQueryWrapper<BaseMold>()
                .in(BaseMold::getBarCode, moldBarcodeList);
        return this.list(wrapper);
    }

    @Override
    public List<BaseMoldVo> getBaseMoldNotinStockDetail(BaseMoldQueryBo bo) {
        return this.baseMapper.getBaseMoldNotinStockDetail(bo);
    }


}
