package com.fjhx.service.material.impl;

import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.entity.classify.Classify;
import com.fjhx.entity.material.Material;
import com.fjhx.entity.stock.Stock;
import com.fjhx.mapper.material.MaterialMapper;
import com.fjhx.params.material.MaterialVo;
import com.fjhx.service.classify.ClassifyService;
import com.fjhx.service.material.MaterialService;
import com.fjhx.service.stock.StockService;
import com.fjhx.uitl.code.CodeEnum;
import com.fjhx.utils.wrapperUtil.IWrapper;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.redis.lock.RedisLockClient;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.entity.Dept;
import org.springblade.system.feign.ISysClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

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

/**
 * <p>
 * 物料 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-11-24
 */
@Service
public class MaterialServiceImpl extends ServiceImpl<MaterialMapper, Material> implements MaterialService {

    @Lazy
    @Autowired
    private ClassifyService classifyService;

    @Autowired
    private StockService stockService;

    @Autowired
    private RedisLockClient redisLockClient;

    @Autowired
    private ISysClient iSysClient;

    private final String REDIS_LOCK_CACHE_KEY = "seq:lock:" + AuthUtil.getTenantId() + ":material:";

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

        IWrapper<Material> wrapper = IWrapper.getWrapper(condition);

        //处理分类
        List<Long> classifyIds = new ArrayList<>();
        if (Func.isNotEmpty(condition.get("classifyId"))) {
            classifyIds.add(Convert.toLong(condition.get("classifyId")));
            //查询所有子级
            List<Classify> classifies = classifyService.lambdaQuery().apply("FIND_IN_SET(" + condition.get("classifyId") + ", parent_id_set)").list();
            if (Func.isNotEmpty(classifies)) {
                classifyIds.addAll(classifies.stream().map(Classify::getId).distinct().collect(Collectors.toList()));
            }
        }

        //处理部门
        List<Long> deptIds = new ArrayList<>();
        if (Func.isNotEmpty(condition.get("deptId"))) {
            deptIds.add(Convert.toLong(condition.get("deptId")));
            //查询所有子级
            List<Dept> depts = iSysClient.getDeptAncestorsById(Convert.toLong(condition.get("deptId")));
            if (Func.isNotEmpty(depts)) {
                deptIds.addAll(depts.stream().map(Dept::getId).distinct().collect(Collectors.toList()));
            }
        }

        wrapper.eq(Material::getType)
                .in(Material::getClassifyId, classifyIds)
                .in(Material::getDeptId, deptIds)
                .apply(Func.isNotEmpty(condition.get("code")), "instr(`code`, '" + condition.get("code") + "') > 0")
                .apply(Func.isNotEmpty(condition.get("name")), "instr(`name`, '" + condition.get("name") + "') > 0")
                .and(Func.isNotEmpty(condition.get("keyword")), o -> o.apply("instr(`code`, '" + condition.get("keyword") + "') > 0").or().apply("instr(`name`, '" + condition.get("keyword") + "') > 0"))
                .orderByDesc(Material::getId);

        Page<Material> page = page(condition, wrapper);
        if (Func.isNotEmpty(page.getRecords())) {
            deptIds = page.getRecords().stream().map(Material::getDeptId).distinct().collect(Collectors.toList());
            //查询部门
            Map<Long, Dept> deptMap = iSysClient.getDeptByIdsToMap(deptIds);

            for (Material record : page.getRecords()) {
                if (Func.isNotEmpty(deptMap) && Func.isEmpty(deptMap.get(record.getDeptId()))) {
                    Dept dept = deptMap.get(record.getDeptId());
                    record.setDeptName(dept.getDeptName());
                }
            }
        }

        return page;
    }

    @Override
    public void add(MaterialVo materialVo) {
        if (
                !redisLockClient.lockFair(REDIS_LOCK_CACHE_KEY, () -> {
                    //获取编码
                    materialVo.setCode(CodeEnum.MATERIAL.getCode());
                    //查询编码是否已存在
                    if (!checkCodeIsExist(null, materialVo.getCode())) {
                        throw new ServiceException("后台自增编码存在重复，请重试或联系管理员！编码：" + materialVo.getCode());
                    }
                    save(materialVo);
                    return true;
                })
        ) {
            throw new ServiceException("当前系统繁忙，请稍后重试！");
        }
    }

    private Boolean checkCodeIsExist(Long id, String code) {
        List<Material> list = lambdaQuery().ne(Func.isNotEmpty(id), Material::getId, id).eq(Material::getCode, code).list();
        if (Func.isNotEmpty(list)) {
            return false;
        }
        return true;
    }

    @Override
    public void edit(MaterialVo materialVo) {
        updateById(materialVo);
    }

    @Override
    public void delete(MaterialVo materialVo) {
        //查询是否存在库存
        List<Stock> stocks = stockService.lambdaQuery().eq(Stock::getGoodsId, materialVo.getId()).list();
        if (Func.isNotEmpty(stocks)) {
            throw new ServiceException("该物料还有库存，无法删除！");
        }
        removeById(materialVo.getId());
    }

}
