package com.fjhx.service.bom.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.base.BaseEntity;
import com.fjhx.constants.ErrorMsgConstant;
import com.fjhx.constants.IotManagementLockConstant;
import com.fjhx.constants.StatusConstant;
import com.fjhx.entity.FileInfo;
import com.fjhx.entity.bom.Bom;
import com.fjhx.entity.bom.BomDetails;
import com.fjhx.enums.bom.BomTypeEnum;
import com.fjhx.mapper.bom.BomMapper;
import com.fjhx.params.bom.BomEx;
import com.fjhx.params.bom.BomVo;
import com.fjhx.service.bom.BomDetailsService;
import com.fjhx.service.bom.BomService;
import com.fjhx.utils.Assert;
import com.fjhx.utils.FileClientUtil;
import com.fjhx.utils.UserClientUtil;
import com.fjhx.utils.WrapperUtil;
import lombok.RequiredArgsConstructor;
import org.springblade.core.redis.lock.RedisLockClient;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * bom 服务实现类
 * </p>
 *
 * @author ${author}
 * @since 2022-07-01
 */
@Service
@RequiredArgsConstructor
public class BomServiceImpl extends ServiceImpl<BomMapper, Bom> implements BomService {

    private final RedisLockClient redisLockClient;

    private final BomDetailsService bomDetailsService;

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

        QueryWrapper<?> wrapper = WrapperUtil.init(condition).eq("p.classify_id", "classifyId") // 产品分类id
                .eq("p.type", "productType") // 产品类型
                .keyword("p.name", "p.code") // 关键字查询
                .getWrapper();

        wrapper.eq("b.type", BomTypeEnum.PRODUCT_TYPE.getCode()); // 产品bom
        wrapper.eq("b.current_edition", StatusConstant.YES); // 当前版本
        wrapper.orderByAsc("p.code"); // 产品编码排序

        Page<BomEx> result = baseMapper.getPage(createPage(condition), wrapper);
        List<BomEx> records = result.getRecords();

        // 赋值最后修改人
        Map<Long, String> userNameMap = UserClientUtil.getUserNameMap(records, Bom::getUpdateUser);

        // 文件信息
        List<Long> fileInfoIdList = records.stream().map(BaseEntity::getId).collect(Collectors.toList());
        Map<Long, FileInfo> fileInfoMap = FileClientUtil.getFileInfoMap(fileInfoIdList);

        records.forEach(item -> {
            item.setUpdateUserName(userNameMap.get(item.getUpdateUser()));
            item.setFileInfo(fileInfoMap.get(item.getId()));
        });

        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(BomVo bomVo) {

        Integer type = bomVo.getType();
        Assert.notEmpty(type, "bom类型不能为空");

        if (type.equals(1)) {
            Integer addType = bomVo.getAddType();
            Assert.notEmpty(addType, "新增类型不能为空");

            Long productId = bomVo.getProductId();
            Assert.notEmpty(productId, "产品id不能为空");

            String edition = bomVo.getEdition();
            Assert.notEmpty(edition, "版本号不能为空");

            // 保证一个产品只有一个bom是启用状态
            Boolean flag = redisLockClient.lockFair(IotManagementLockConstant.BOM_EDITION_LOCK + productId, () -> {
                List<Bom> list = list(Bom::getProductId, productId);

                // 新增产品逻辑
                if (addType == 1) {
                    Assert.eqZero(list.size(), "产品已添加");
                    bomVo.setCurrentEdition(StatusConstant.YES);
                }
                // 新建版本逻辑
                else {
                    Assert.gtZero(list.size(), "未添加过产品");

                    long count = list.stream().filter(item -> edition.equals(item.getEdition())).count();
                    Assert.eqZero(count, "此版本已存在");
                    bomVo.setCurrentEdition(StatusConstant.NO);
                }

                save(bomVo);
                return true;
            });

            Assert.eqTrue(flag, ErrorMsgConstant.SYSTEM_BUSY_ERROR);
        } else {
            String packName = bomVo.getPackName();
            Assert.notEmpty(packName, "包装bom名称不能为空");
            save(bomVo);
        }

        // bom明细
        List<BomDetails> bomDetailsList = bomVo.getBomDetailsList();
        if (bomDetailsList.size() > 0) {
            bomDetailsList.forEach(item -> item.setBomId(bomVo.getId()));
            bomDetailsService.saveBatch(bomDetailsList);
        }

        // 绑定文件
        FileClientUtil.bindingFile(bomVo.getId(), bomVo.getFileInfo());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BomVo bomVo) {
        Long id = bomVo.getId();
        Assert.notEmpty(id, "bomId不能为空");

        // 如果包装名称不为空
        String packName = bomVo.getPackName();
        if (ObjectUtil.isNotEmpty(packName)) {
            updateById(bomVo);
        }

        // 删除bom明细
        List<Long> deleteBomIdList = bomVo.getDeleteBomIdList();
        if (deleteBomIdList.size() > 0) {
            bomDetailsService.removeByIds(deleteBomIdList);
        }

        // 新增或编辑bom明细
        List<BomDetails> bomDetailsList = bomVo.getBomDetailsList();
        if (bomDetailsList.size() > 0) {
            bomDetailsList.forEach(item -> item.setBomId(bomVo.getId()));
            bomDetailsService.saveOrUpdateBatch(bomDetailsList);
        }

        // 重新绑定
        FileClientUtil.againBindingFile(bomVo.getId(), bomVo.getFileInfo());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(BomVo bomVo) {
        removeById(bomVo.getId());
        bomDetailsService.remove(q -> q.eq(BomDetails::getBomId, bomVo.getId()));
    }

    @Override
    public List<Map<String, Object>> getBomRelationProductClassify() {
        return baseMapper.getBomRelationProductClassify();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateVersion(Bom bom) {

        Long productId = bom.getProductId();
        Assert.notEmpty(productId, "产品id不能为空");

        Long id = bom.getId();
        Assert.notEmpty(id, "启用bom版本id不能为空");

        // 保证一个产品只有一个bom是启用状态
        Boolean flag = redisLockClient.lockFair(IotManagementLockConstant.BOM_EDITION_LOCK + productId, () -> {
            update(q -> q.eq(Bom::getProductId, productId).set(Bom::getCurrentEdition, StatusConstant.NO));
            update(q -> q.eq(BaseEntity::getId, id).set(Bom::getCurrentEdition, StatusConstant.YES));
            return true;
        });
        Assert.eqTrue(flag, ErrorMsgConstant.SYSTEM_BUSY_ERROR);
    }

}
