package com.xisc.pm.app.service.impl;

import com.xisc.boot.common.feign.pojo.MtUserInfo;
import com.xisc.boot.common.sys.UserClient;
import com.xisc.pm.api.dto.PmSlabMethodDTO;
import com.xisc.pm.app.service.PmSlabMethodService;
import com.xisc.pm.domain.entity.PmSlabMethod;
import com.xisc.pm.domain.repository.PmSlabMethodRepository;
import com.xisc.pm.infra.mapper.PmSlabMethodMapper;
import io.choerodon.core.domain.Page;
import io.choerodon.core.exception.CommonException;
import io.choerodon.mybatis.pagehelper.PageHelper;
import io.choerodon.mybatis.pagehelper.domain.PageRequest;
import org.apache.commons.collections.CollectionUtils;
import org.apache.logging.log4j.util.Strings;
import org.hzero.mybatis.domian.Condition;
import org.hzero.mybatis.util.Sqls;
import org.jgrapht.alg.util.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 生产线组板方式表(PmSlabMethod)应用服务
 *
 * @author jie.yang04@hand-china.com
 * @since 2024-10-09 09:43:34
 */
@Service
public class PmSlabMethodServiceImpl implements PmSlabMethodService {
    @Autowired
    private PmSlabMethodRepository pmSlabMethodRepository;

    @Autowired
    private PmSlabMethodMapper pmSlabMethodMapper;

    @Autowired
    private UserClient userClient;

    @Override
    public Page<PmSlabMethod> selectList(PageRequest pageRequest, PmSlabMethod pmSlabMethod) {
        return PageHelper.doPageAndSort(pageRequest, () -> pmSlabMethodRepository.selectList(pmSlabMethod));
    }

    @Override
    public Page<PmSlabMethodDTO> selectByProdLineIdList(PageRequest pageRequest, Long tenantId, Long prodLineId) {
        if (Objects.isNull(prodLineId)) {
            return new Page<>();
        }
        Page<PmSlabMethodDTO> objectPage = PageHelper.doPageAndSort(pageRequest, () -> pmSlabMethodMapper.selectByProdLineIdList(tenantId, prodLineId));
        // 初始化一个用户ID列表，用于存储生产线路的创建人和最后更新人的用户ID
        List<Long> userIds = new ArrayList<>(16);
        // 添加创建人的用户ID到用户ID列表中
        userIds.addAll(objectPage.getContent().stream().map(PmSlabMethodDTO::getCreatedBy).distinct().collect(Collectors.toList()));
        // 添加最后更新人的用户ID到用户ID列表中
        userIds.addAll(objectPage.getContent().stream().map(PmSlabMethodDTO::getLastUpdatedBy).distinct().collect(Collectors.toList()));

        // 调用userClient的userInfoBatchGet方法，批量获取用户信息
        Map<Long, MtUserInfo> mtUserInfoMap = userClient.userInfoBatchGet(tenantId, userIds);

        // 遍历生产线路列表，设置创建人和最后更新人的名称
        objectPage.getContent().forEach(line -> {
            // 获取创建人名称
            if (!mtUserInfoMap.isEmpty() && mtUserInfoMap.containsKey(line.getCreatedBy())) {
                MtUserInfo mtUserInfo = mtUserInfoMap.get(line.getCreatedBy());
                line.setCreatedByName(Strings.concat(mtUserInfo.getLoginName(), mtUserInfo.getRealName()));
            }
            // 获取更新人名称
            if (!mtUserInfoMap.isEmpty() && mtUserInfoMap.containsKey(line.getLastUpdatedBy())) {
                MtUserInfo mtUserInfo = mtUserInfoMap.get(line.getLastUpdatedBy());
                line.setUpdateByName(Strings.concat(mtUserInfo.getLoginName(), mtUserInfo.getRealName()));
            }
        });
        return objectPage;
    }

    /**
     * 保存生产线方法配置数据
     *
     * @param tenantId 租户ID，用于区分不同的租户数据
     * @param pmSlabMethods 待保存的生产线方法配置列表
     */
    @Override
    public void saveData(Long tenantId, List<PmSlabMethod> pmSlabMethods) {
        // 如果输入的生产线方法配置列表为空，则直接返回，无需进行后续操作
        if (CollectionUtils.isEmpty(pmSlabMethods)) {
            return;
        }

        // 为每个生产线方法配置设置租户ID
        pmSlabMethods.forEach(x -> x.setTenantId(tenantId));

        // 收集所有待保存的生产线方法配置所涉及的生产线ID，并去除重复
        List<Long> prodLineIds = pmSlabMethods.stream().map(PmSlabMethod::getProdLineId).distinct().collect(Collectors.toList());

        // 查询已存在的生产线方法配置，以便进行冲突检查
        List<PmSlabMethod> eixstsSlabMethodList = pmSlabMethodRepository
                .selectByCondition(Condition.builder(PmSlabMethod.class)
                        .andWhere(Sqls.custom().andIn(PmSlabMethod.FIELD_PROD_LINE_ID, prodLineIds))
                        .andWhere(Sqls.custom().andEqualTo(PmSlabMethod.FIELD_TENANT_ID, tenantId)).build());

        // 如果已存在的生产线方法配置列表不为空，则进行冲突检查
        if (CollectionUtils.isNotEmpty(eixstsSlabMethodList)) {
            // 将已存在的生产线方法配置以生产线ID和优先级为键，存入Map中，用于快速查找
            Map<Pair<Long, Long>, PmSlabMethod> pmSlabMethodPriorityMap = eixstsSlabMethodList.stream().collect(Collectors.toMap(x -> Pair.of(x.getProdLineId(), x.getPriority()), t -> t));
            // 将已存在的生产线方法配置以生产线ID和组合坯料方法为键，存入Map中，用于快速查找
            Map<Pair<Long, String>, PmSlabMethod> pmSlabMethodComboMap = eixstsSlabMethodList.stream().collect(Collectors.toMap(x -> Pair.of(x.getProdLineId(), x.getComboSlabMethod()), t -> t));

            // 遍历所有待保存的生产线方法配置，检查是否存在冲突
            for (PmSlabMethod pmSlabMethod : pmSlabMethods) {
                // 如果在已存在的配置中找到了相同生产线ID和优先级的配置，抛出异常，提示冲突
                if (pmSlabMethodPriorityMap.containsKey(Pair.of(pmSlabMethod.getProdLineId(), pmSlabMethod.getPriority()))
                        && (Objects.isNull(pmSlabMethod.getProdLineStatsId()) || pmSlabMethodPriorityMap.get(Pair.of(pmSlabMethod.getProdLineId(), pmSlabMethod.getPriority())).getProdLineStatsId().compareTo(pmSlabMethod.getProdLineStatsId()) != 0)) {
                    throw new CommonException("pm.producation_line_003", pmSlabMethod.getProdLineCode(), pmSlabMethod.getPriority());
                }
                // 如果在已存在的配置中找到了相同生产线ID和组合坯料方法的配置，抛出异常，提示冲突
                if (pmSlabMethodComboMap.containsKey(Pair.of(pmSlabMethod.getProdLineId(), pmSlabMethod.getComboSlabMethod()))
                        && (Objects.isNull(pmSlabMethod.getProdLineStatsId()) || pmSlabMethodComboMap.get(Pair.of(pmSlabMethod.getProdLineId(), pmSlabMethod.getComboSlabMethod())).getProdLineStatsId().compareTo(pmSlabMethod.getProdLineStatsId()) != 0)) {
                    throw new CommonException("pm.producation_line_004", pmSlabMethod.getProdLineCode(), pmSlabMethod.getComboSlabMethod());
                }
            }
        }

        // 将待保存的生产线方法配置分为需要插入的新记录和需要更新的已有记录
        List<PmSlabMethod> insertList = pmSlabMethods.stream().filter(line -> line.getProdLineStatsId() == null).collect(Collectors.toList());
        List<PmSlabMethod> updateList = pmSlabMethods.stream().filter(line -> line.getProdLineStatsId() != null).collect(Collectors.toList());

        // 批量插入新记录
        pmSlabMethodRepository.batchInsertSelective(insertList);
        // 批量更新已有记录
        pmSlabMethodRepository.batchUpdateByPrimaryKeySelective(updateList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteData(Long tenantId, List<Long> prodLineStatsIds) {
        // 检查生产线ID列表是否为空，如果为空则直接返回，不进行后续操作
        if (CollectionUtils.isEmpty(prodLineStatsIds)) {
            return;
        }
        // 根据条件查询需要删除的生产线数据
        List<PmSlabMethod> pmSlabMethodList = pmSlabMethodRepository.selectByCondition(Condition.builder(PmSlabMethod.class)
                .andWhere(Sqls.custom().andIn(PmSlabMethod.FIELD_PROD_LINE_STATS_ID, prodLineStatsIds))
                .andWhere(Sqls.custom().andEqualTo(PmSlabMethod.FIELD_TENANT_ID, tenantId)).build());
        // 批量删除查询到的生产线数据
        pmSlabMethodRepository.batchDeleteByPrimaryKey(pmSlabMethodList);
    }
}

