package com.fjhx.mes.service.bom.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.file.utils.ObsFileUtil;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.mes.entity.bom.dto.BomInfoDto;
import com.fjhx.mes.entity.bom.dto.BomInfoSelectDto;
import com.fjhx.mes.entity.bom.po.BomDetail;
import com.fjhx.mes.entity.bom.po.BomInfo;
import com.fjhx.mes.entity.bom.vo.BomDetailVo;
import com.fjhx.mes.entity.bom.vo.BomInfoVo;
import com.fjhx.mes.entity.bom.vo.BomProductVo;
import com.fjhx.mes.mapper.bom.BomInfoMapper;
import com.fjhx.mes.service.bom.BomDetailService;
import com.fjhx.mes.service.bom.BomInfoService;
import com.ruoyi.common.constant.StatusConstant;
import com.ruoyi.common.core.domain.BaseIdPo;
import com.ruoyi.common.core.domain.BasePo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.common.utils.wrapper.SqlField;
import com.ruoyi.system.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p>
 * bom 服务实现类
 * </p>
 *
 * @author
 * @since 2023-03-29
 */
@Service
public class BomInfoServiceImpl extends ServiceImpl<BomInfoMapper, BomInfo> implements BomInfoService {

    @Autowired
    private ProductInfoService productInfoService;

    @Autowired
    private BomDetailService bomDetailService;

    @Override
    public Page<BomInfoVo> getPage(BomInfoSelectDto dto) {

        Integer productType = dto.getProductType();
        String keyword = dto.getKeyword();

        Map<Long, ProductInfo> productInfoMap = new HashMap<>();
        if (!ObjectUtil.isAllEmpty(productType, keyword)) {
            List<ProductInfo> list = productInfoService.list(IWrapper.<ProductInfo>getWrapper()
                    .eq(ProductInfo::getType, productType)
                    .keyword(keyword, new SqlField(ProductInfo::getName), new SqlField(ProductInfo::getCode)));

            if (list.size() == 0) {
                return new Page<>();
            }

            productInfoMap = list.stream().collect(Collectors.toMap(BaseIdPo::getId, Function.identity()));
        }

        IWrapper<BomInfo> wrapper = getWrapper()
                .in("bi", BomInfo::getProductId, productInfoMap.keySet())
                .eq("bi", BomInfo::getCurrentVersion, StatusConstant.YES)
                .orderByDesc("bi", BomInfo::getId);

        Page<BomInfoVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<BomInfoVo> records = page.getRecords();

        if (records.size() == 0) {
            return page;
        }

        // 赋值最近维护人
        UserUtil.assignmentNickName(records, BasePo::getUpdateUser, BomInfoVo::setUpdateUserName);

        if (productInfoMap.size() > 0) {
            for (BomInfoVo item : records) {
                ProductInfo productInfo = productInfoMap.get(item.getProductId());
                item.setProductType(productInfo.getType());
                item.setProductCode(productInfo.getCode());
                item.setProductName(productInfo.getName());
            }
        } else {
            productInfoService.attributeAssign(records, BomInfo::getProductId, (item, productInfo) -> {
                item.setProductType(productInfo.getType());
                item.setProductCode(productInfo.getCode());
                item.setProductName(productInfo.getName());
            });
        }

        return page;
    }

    @Override
    public BomInfoVo detail(Long id) {
        BomInfo BomInfo = this.getById(id);
        BomInfoVo result = BeanUtil.toBean(BomInfo, BomInfoVo.class);

        List<BomDetail> bomDetailList = bomDetailService.list(q -> q.eq(BomDetail::getBomInfoId, id));
        List<BomDetailVo> bomDetailVoList = BeanUtil.copyToList(bomDetailList, BomDetailVo.class);

        productInfoService.attributeAssign(bomDetailVoList, BomDetailVo::getProductId, (item, productInfo) -> {
            item.setProductCode(productInfo.getCode());
            item.setProductName(productInfo.getName());
            item.setProductUnit(productInfo.getUnit());
        });

        result.setBomDetailVoList(bomDetailVoList);
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(BomInfoDto bomInfoDto) {

        // 新建bom
        if (bomInfoDto.getAddType().equals(1)) {
            nameDuplication(BomInfo::getProductId, bomInfoDto.getProductId(), "该产品已存在 BOM，请新建版本或进行修改操作");
            bomInfoDto.setVersionNumber(1);
            bomInfoDto.setCurrentVersion(StatusConstant.YES);
        }
        // 新建bom版本
        else {
            long count = count(q -> q.eq(BomInfo::getProductId, bomInfoDto.getProductId()));
            bomInfoDto.setVersionNumber(Convert.toInt(count + 1));
            bomInfoDto.setCurrentVersion(StatusConstant.NO);
        }

        bomInfoDto.setStatus(StatusConstant.ENABLE);
        this.save(bomInfoDto);

        // 添加bom明细
        List<BomDetail> bomDetailList = bomInfoDto.getBomDetailList();
        if (ObjectUtil.isNotEmpty(bomDetailList)) {
            for (BomDetail bomDetail : bomDetailList) {
                bomDetail.setBomInfoId(bomInfoDto.getId());
            }
            bomDetailService.saveBatch(bomDetailList);
        }

    }

    @Override
    public void edit(BomInfoDto bomInfoDto) {
        Long bomInfoId = bomInfoDto.getId();
        if (ObjectUtil.isEmpty(bomInfoId)) {
            throw new ServiceException("bomId不能为空");
        }

        bomInfoDto.setCurrentVersion(null);
        bomInfoDto.setVersionNumber(null);

        this.updateById(bomInfoDto);

        // 更新bom明细
        List<BomDetail> bomDetailList = bomInfoDto.getBomDetailList();
        if (ObjectUtil.isNotEmpty(bomDetailList)) {

            List<Long> bomDetailIdList = bomDetailList.stream()
                    .peek(item -> item.setBomInfoId(bomInfoId))
                    .map(BaseIdPo::getId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

            bomDetailService.remove(q -> q
                    .eq(BomDetail::getBomInfoId, bomInfoId)
                    .notIn(ObjectUtil.isNotEmpty(bomDetailIdList), BaseIdPo::getId, bomDetailIdList));

            bomDetailService.saveOrUpdateBatch(bomDetailList);
        }

    }

    @Override
    public List<BomInfo> getVersion(Long productId) {
        if (ObjectUtil.isEmpty(productId)) {
            throw new ServiceException("产品id不能为空");
        }
        return list(q -> q.eq(BomInfo::getProductId, productId));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editVersion(BomInfo bomInfo) {
        Long productId = bomInfo.getProductId();
        Integer versionNumber = bomInfo.getVersionNumber();

        if (ObjectUtil.isEmpty(productId)) {
            throw new ServiceException("产品id不能为空");
        }
        if (ObjectUtil.isEmpty(versionNumber)) {
            throw new ServiceException("切换版本号不能为空");
        }

        update(q -> q
                .eq(BomInfo::getProductId, productId)
                .ne(BomInfo::getVersionNumber, versionNumber)
                .set(BomInfo::getCurrentVersion, StatusConstant.NO));

        update(q -> q
                .eq(BomInfo::getProductId, productId)
                .eq(BomInfo::getVersionNumber, versionNumber)
                .set(BomInfo::getCurrentVersion, StatusConstant.YES));

    }

    @DSTransactional
    @Override
    public void addByJxst(BomInfoDto bomInfoDto) {
        add(bomInfoDto);
        ObsFileUtil.saveFile(bomInfoDto.getFileList(), bomInfoDto.getId());
    }

    @DSTransactional
    @Override
    public void editByJxst(BomInfoDto bomInfoDto) {
        edit(bomInfoDto);
        ObsFileUtil.editFile(bomInfoDto.getFileList(), bomInfoDto.getId());
    }

    @Override
    public List<BomProductVo> getProductList() {
        List<ProductInfo> list = productInfoService.list();
        List<BomProductVo> bomProductList = BeanUtil.copyToList(list, BomProductVo.class);

        List<Long> productIdList = listObject(BomInfo::getProductId, null);
        bomProductList.forEach(item -> item.setDisabled(productIdList.contains(item.getId())));
        return bomProductList;
    }

}
