package com.shkj.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.shkj.common.annotation.DataScopeConsignor;
import com.shkj.common.core.domain.Result;
import com.shkj.common.enums.IsDelEnum;
import com.shkj.common.utils.SecurityUtils;
import com.shkj.common.utils.StringUtils;
import com.shkj.wms.bo.*;
import com.shkj.wms.config.ValidList;
import com.shkj.wms.domain.BaseContainer;
import com.shkj.wms.domain.SysStockDetail;
import com.shkj.wms.enums.ContainerStausEnum;
import com.shkj.wms.enums.ContainerTypeEnum;
import com.shkj.wms.mapper.BaseContainerMapper;
import com.shkj.wms.service.IBaseContainerService;
import com.shkj.wms.service.ISysStockDetailService;
import com.shkj.wms.vo.BaseContainerInWWarehoseVo;
import com.shkj.wms.vo.BaseContainerVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestBody;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 托盘资料Service业务层处理
 *
 * @author lch
 * @date 2022-04-23
 */
@Slf4j
@Service
public class BaseContainerServiceImpl extends ServiceImpl<BaseContainerMapper, BaseContainer> implements IBaseContainerService {

    @Autowired
    ISysStockDetailService iSysStockDetailService;

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

    @Override
    public List<BaseContainerVo> queryList(BaseContainerQueryBo bo) {
        LambdaQueryWrapper<BaseContainer> lqw = Wrappers.lambdaQuery();
        lqw.eq(StrUtil.isNotBlank(bo.getContainerCode()), BaseContainer::getContainerCode, bo.getContainerCode());
        lqw.like(StrUtil.isNotBlank(bo.getContainerName()), BaseContainer::getContainerName, bo.getContainerName());
        lqw.eq(StrUtil.isNotBlank(bo.getContainerType()), BaseContainer::getContainerType, bo.getContainerType());
        lqw.eq(StrUtil.isNotBlank(bo.getStatus()), BaseContainer::getStatus, bo.getStatus());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend1()), BaseContainer::getExtend1, bo.getExtend1());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend2()), BaseContainer::getExtend2, bo.getExtend2());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend3()), BaseContainer::getExtend3, bo.getExtend3());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend4()), BaseContainer::getExtend4, bo.getExtend4());
        lqw.eq(StrUtil.isNotBlank(bo.getExtend5()), BaseContainer::getExtend5, bo.getExtend5());
        lqw.eq(bo.getBranchId() != null, BaseContainer::getBranchId, bo.getBranchId());
        lqw.eq(StrUtil.isNotBlank(bo.getIsDel()), BaseContainer::getIsDel, bo.getIsDel());
        lqw.eq(BaseContainer::getIsDel, IsDelEnum.NORMAL.getValue());
        lqw.orderByDesc(BaseContainer::getCreateTime);
        List<BaseContainerVo> voList = entity2Vo(this.list(lqw));
        return voList;

    }

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

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> insertByAddBo(BaseContainerAddBo bo) {
        BaseContainer add = BeanUtil.toBean(bo, BaseContainer.class);
        this.save(add);
        return Result.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> updateByEditBo(BaseContainerEditBo bo) {
        BaseContainer one = getById(bo.getId());
        if (one == null) {
            return Result.err().msg("不存在");
        }
        BaseContainer update = BeanUtil.toBean(bo, BaseContainer.class);
        this.updateById(update);
        return Result.ok();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> deleteWithValidById(List<Long> ids, Boolean isValid) {
        BaseContainer del = new BaseContainer();
        del.setIsDel(IsDelEnum.DELETED.getValue());
        LambdaQueryWrapper<BaseContainer> wrapper = new LambdaQueryWrapper<BaseContainer>().in(BaseContainer::getId, ids)
                .eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId());
        this.update(del, wrapper);
        return Result.ok();
    }

    @Override
    public Boolean updateById(Long id) {
        BaseContainer update = new BaseContainer();
        update.setStatus(ContainerStausEnum.NO_FULL.getValue());
        LambdaQueryWrapper<BaseContainer> wrapper = new LambdaQueryWrapper<BaseContainer>().eq(BaseContainer::getId, id)
                .eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId());
        return this.update(update, wrapper);
    }


    /**
     * 托盘编号录入后，需要校验与商品存储分类是否匹配：
     * <p>
     * 存储分类为整散分开的商品，零散数数量不为0，绑定托盘类型需为周转箱；件数数量不为0，绑定托盘类型需为托盘；（若已经绑定托盘后，件数/零散数发生变化，自动清空托盘）；
     * <p>
     * 整散合一的商品绑定托盘类型为托盘；
     * <p>
     * 提示：“请选择正确的托盘类型”
     *
     * @param containerCode
     * @return
     */
    @Override
    public Result<BaseContainerVo> checkBaseContainer(String containerCode) {
        LambdaQueryWrapper<BaseContainer> lqw = Wrappers.lambdaQuery();
        lqw.eq(BaseContainer::getContainerCode, containerCode);
        lqw.eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId()).last("limit 1");
        BaseContainer baseContainer = this.getOne(lqw);
        if (baseContainer == null) {
            return Result.err().msg("该托盘不存在");
        } else if (baseContainer.getStatus().equals(ContainerStausEnum.FULL.getValue())) {
            return Result.err().msg("托盘已经使用，请使用新托盘", baseContainer.getContainerCode());
        }

        return Result.ok().data(BeanUtil.toBean(baseContainer, BaseContainerVo.class));
    }

    @Override
    public Result<BaseContainerVo> checkContainerCodeNoInv(String containerCode) {
        LambdaQueryWrapper<BaseContainer> lqw = Wrappers.lambdaQuery();
        lqw.eq(BaseContainer::getContainerCode, containerCode);
        lqw.eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId()).last("limit 1");
        BaseContainer baseContainer = this.getOne(lqw);


        if (baseContainer == null) {
            return Result.err().msg("该托盘不存在");
        } else if (baseContainer.getStatus().equals(ContainerStausEnum.FULL.getValue())) {
            return Result.err().msg("托盘已经使用，请使用新托盘", baseContainer.getContainerCode());
        }

        LambdaQueryWrapper<SysStockDetail> lqwd = Wrappers.lambdaQuery();
        lqwd.eq(SysStockDetail::getContainerCode, containerCode);
        lqwd.eq(SysStockDetail::getBranchId, SecurityUtils.getCurrentBranchId()).last("limit 1");
        SysStockDetail one = iSysStockDetailService.getOne(lqwd);
        if (one != null) {
            return Result.err().msg("该货位已有托盘");
        }
        return Result.ok().data(BeanUtil.toBean(baseContainer, BaseContainerVo.class));
    }

    @Override
    public List<BaseContainerVo> getContainerNoInv() {
        return this.baseMapper.getContainerNoInv();
    }


    @Override
    public Result checkChangeTray(Long containerId) {
        BaseContainer container = this.getById(containerId);
        if (container == null) {
            return Result.err().msg("该托盘不存在");
        }
        if (container.getContainerType().equals(ContainerTypeEnum.TRAY.getValue()) && container.getStatus().equals(ContainerStausEnum.FULL.getValue())) {
            return Result.err().msg("托盘已经使用，请使用新托盘", container.getContainerCode());
        }
        return Result.ok();
    }

    @Override
    @Async
    public void releaseContainer(List<Long> containerIds) {
        //释放托盘
        log.info("释放托盘 = {}", containerIds);
        if (containerIds.size() == 0) {
            return;
        }
        //判断当前托盘是否有任务，如果存在任务，则不进行托盘释放；不存在任务，进行托盘释放，将托盘状态从1修改成0；
        List<BaseContainer> baseContainers = this.baseMapper.queryNoUserContainer(containerIds);
        List<Long> useIds = baseContainers.stream().map(x -> x.getId()).collect(Collectors.toList());
        containerIds.removeAll(useIds);
        BaseContainer container = new BaseContainer();
        container.setStatus(ContainerStausEnum.FREE.getValue());
        if (containerIds.size() == 0) {
            return;
        }
        log.info("释放托盘 = {}", containerIds);
        update(container, new LambdaQueryWrapper<BaseContainer>().in(BaseContainer::getId, containerIds));
    }

    /**
     * 根据托盘编号获取托盘对象
     *
     * @param containerCode 托盘编号
     * @return
     */
    @Override
    public Result<BaseContainer> queryBaseContainerByCode(String containerCode) {
        LambdaQueryWrapper<BaseContainer> lqw = Wrappers.lambdaQuery();
        lqw.eq(BaseContainer::getContainerCode, containerCode);
        lqw.eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId());
        List<BaseContainer> list = this.list(lqw);
        if (list == null || list.size() == 0) {
            return Result.err().msg("该托盘不存在");
        }
        if (list.size() > 1) {
            return Result.err().msg("托盘异常，存在脏数据");
        }
        return Result.ok().data(list.get(0));
    }

    @Override
    public BaseContainer queryContainerByCode(String containerCode) {
        LambdaQueryWrapper<BaseContainer> lqw = Wrappers.lambdaQuery();
        lqw.eq(BaseContainer::getContainerCode, containerCode);
        lqw.eq(BaseContainer::getIsDel, IsDelEnum.NORMAL.getValue());
        //lqw.eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId());
        lqw.eq(BaseContainer::getBranchId, "3");
        lqw.last("limit 1");
        return getOne(lqw);
    }

    /**
     * 根据code集合获取对应的托盘信息
     *
     * @param codeList
     * @return
     */
    public List<BaseContainer> queryContainersByCodes(List<String> codeList) {
        LambdaQueryWrapper<BaseContainer> lqw = Wrappers.lambdaQuery();
        lqw.in(BaseContainer::getContainerCode, codeList);
        lqw.eq(BaseContainer::getIsDel, IsDelEnum.NORMAL.getValue());
        lqw.eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId());
        return list(lqw);
    }

    /**
     * 根据集合获取对应的托盘信息
     *
     * @param ids
     * @return
     */
    public List<BaseContainer> queryContainersByIds(List<Long> ids, String status) {
        LambdaQueryWrapper<BaseContainer> lqw = Wrappers.lambdaQuery();
        lqw.in(BaseContainer::getId, ids);
        if (StringUtils.isNotBlank(status)) {
            lqw.eq(BaseContainer::getStatus, status);
        }
        lqw.eq(BaseContainer::getIsDel, IsDelEnum.NORMAL.getValue());
        lqw.eq(BaseContainer::getBranchId, SecurityUtils.getCurrentBranchId());
        return list(lqw);
    }

    /**
     * 查查看具有权限的托盘资料列表
     *
     * @param bo
     * @return
     */
    @Override
    @DataScopeConsignor(branchAlias = "bc")
    public List<BaseContainerVo> queryBaseContainerList(BaseContainerQueryListBo bo) {
        return this.getBaseMapper().queryBaseContainerList(bo);
    }

    /**
     * 保存或者修改托盘资料（根据是否有id来判断新增或者修改）
     *
     * @param list
     * @return
     */
    @Override
    public Result<Boolean> saveOrUpdateBaseContainers(@Valid @RequestBody ValidList<BaseContainerSaveOrUpdateBo> list) {
        List<BaseContainer> addList = new ArrayList<>();
        List<BaseContainer> updList = new ArrayList<>();

        Set<String> listGroup = list.stream().collect(Collectors.groupingBy(item ->
                item.getId()
                        + "-" + item.getContainerCode())).keySet();
        if (listGroup.size() != list.size()) {
            log.error("请求参数存在重复数据");
            return Result.err().msg("请求参数存在重复数据");
        }

        for (BaseContainerSaveOrUpdateBo bo : list) {
            if (bo.getId() != null) {
                BaseContainer one = getById(bo.getId());
                if (one == null) {
                    log.error("托盘资料不存在:" + bo.toString());
                    return Result.err().msg("托盘资料不存在");
                }

                BaseContainer update = BeanUtil.toBean(bo, BaseContainer.class);
                update.setBranchId(one.getBranchId());
                Result result = checkEntity(update);
                if (!Result.isOk(result)) {
                    return Result.err().msg(result.getMsg());
                }
                updList.add(update);
            } else {
                BaseContainer add = BeanUtil.toBean(bo, BaseContainer.class);
                add.setBranchId(SecurityUtils.getCurrentBranchId());
                Result result = checkEntity(add);
                if (!Result.isOk(result)) {
                    return Result.err().msg(result.getMsg());
                }
                addList.add(add);
            }
        }
        this.updateBatchById(updList);
        this.saveBatch(addList);
        return Result.ok();
    }

    /**
     * 校验数据 (code不允许重复)
     *
     * @param entity
     * @return
     */
    private Result checkEntity(BaseContainer entity) {
        Long id = entity.getId() != null ? entity.getId() : -1L;
        LambdaQueryWrapper<BaseContainer> wrapper = new LambdaQueryWrapper<BaseContainer>()
                .eq(BaseContainer::getBranchId, entity.getBranchId())
                .eq(BaseContainer::getContainerCode, entity.getContainerCode())
                .eq(BaseContainer::getIsDel, IsDelEnum.NORMAL.getValue());
        BaseContainer one = getOne(wrapper);
        if (one != null && !id.equals(one.getId())) {
            log.error("存在重复数据：" + entity.toString());
            return Result.err().msg("存在重复数据");
        }
        return Result.ok();
    }

    /**
     * 删除空闲的托盘资料
     *
     * @param ids
     * @return
     */
    @Override
    public Result<Boolean> removeBaseContainers(ValidList<Long> ids) {
        // 根据ids获取非空闲的数据
        List<BaseContainer> list = this.queryContainersByIds(ids, ContainerStausEnum.NO_FULL.getValue());
        if (CollectionUtils.isNotEmpty(list)) {
            return Result.err().msg("存在托盘状态为占用状态，不允许删除");
        }
        return deleteWithValidById(ids, true);
    }

    /**
     * 批量保存托盘数据
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional
    public Result<Boolean> saveManyBaseContainers(BaseContainerManySaveBo bo) {
        // 校验起始终止编号的正确性
        if (bo.getStartCode() < 0L || bo.getEndCode() < 0L || bo.getStartCode() > bo.getEndCode()) {
            log.error("起始终止编号存在错误:" + bo.toString());
            return Result.err().msg("起始终止编号存在错误");
        }
        // 获取起始终止编码之间的数据
        List<String> listCodes = new ArrayList<String>();
        List<BaseContainer> listBaseContainers = new ArrayList<BaseContainer>();
        for (Long a = bo.getStartCode(); a <= bo.getEndCode(); a++) {
            listCodes.add((StringUtils.isBlank(bo.getPreCode()) ? "" : bo.getPreCode()) + a.toString());
        }
        // 检验是否存在重复的code
        List<BaseContainer> listContainers = queryContainersByCodes(listCodes);
        if (CollectionUtils.isNotEmpty(listContainers)) {
            return Result.err().msg("托盘编号存在重复");
        }
        for (Long a = bo.getStartCode(); a <= bo.getEndCode(); a++) {
            BaseContainer baseContainer = new BaseContainer();
            baseContainer.setContainerCode(a.toString());
            baseContainer.setContainerType(bo.getContainerType());
            baseContainer.setStatus(bo.getStatus());
            baseContainer.setBranchId(SecurityUtils.getCurrentBranchId());
            listBaseContainers.add(baseContainer);
        }
        this.saveBatch(listBaseContainers);
        return Result.ok();
    }


    /**
     * 查查看具有权限的托盘资料列表
     *
     * @param bo
     * @return
     */
    @Override
    public List<BaseContainerInWWarehoseVo> queryContainerInWWarehoseList(BaseContainerQueryListBo bo) {
        return this.getBaseMapper().queryContainerInWWarehoseList(bo);
    }

    @Override
    public Result<Boolean> switchStatus(Long id, String status) {
        BaseContainer container = new BaseContainer();
        container.setId(id).setStatus(status);
        return this.updateById(container) ? Result.ok() : Result.err();
    }
}
