package com.zt.plat.module.qms.resource.material.dal.mapper;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.zt.plat.framework.mybatis.core.query.MPJLambdaWrapperX;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.qms.business.config.dal.dataobject.ConfigWarehouseLocationDO;
import com.zt.plat.module.qms.core.constant.DataTypeConstant;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialProductPageReqVO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.*;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

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

/**
 * 物料大类 Mapper
 *
 * @author 后台管理
 */
@Mapper
public interface MaterialProductMapper extends BaseMapperX<MaterialProductDO> {

    default PageResult<MaterialProductDO> selectPage(MaterialProductPageReqVO reqVO) {
        LambdaQueryWrapper<MaterialProductDO> wrapper = new LambdaQueryWrapperX<MaterialProductDO>()
                .eq(MaterialProductDO::getNodeType, DataTypeConstant.DATA_TYPE_DATA)
                .eqIfPresent(MaterialProductDO::getParentId, reqVO.getParentId())
                .eqIfPresent(MaterialProductDO::getInventoryAlarmLevel, reqVO.getInventoryAlarmLevel())
                .likeIfPresent(MaterialProductDO::getIdPath, reqVO.getIdPath())
                .likeIfPresent(MaterialProductDO::getName, reqVO.getName())
                .likeIfPresent(MaterialProductDO::getCode, reqVO.getCode())
                .likeIfPresent(MaterialProductDO::getCustomConfig, reqVO.getCustomConfig())
                .likeIfPresent(MaterialProductDO::getCustomForm, reqVO.getCustomForm())
                .likeIfPresent(MaterialProductDO::getCustomData, reqVO.getCustomData())
                .likeIfPresent(MaterialProductDO::getTag, reqVO.getTag())
                .likeIfPresent(MaterialProductDO::getLabelTemplateKey, reqVO.getLabelTemplateKey())
                .likeIfPresent(MaterialProductDO::getModelNo, reqVO.getModelNo())
                .likeIfPresent(MaterialProductDO::getSpecification, reqVO.getSpecification())
                .likeIfPresent(MaterialProductDO::getParameter, reqVO.getParameter())
                .likeIfPresent(MaterialProductDO::getManufacturer, reqVO.getManufacturer())
                .eqIfPresent(MaterialProductDO::getUnit, reqVO.getUnit())
                .eqIfPresent(MaterialProductDO::getEnablePartial, reqVO.getEnablePartial())
                .betweenIfPresent(MaterialProductDO::getDue, reqVO.getDue())
                .eqIfPresent(MaterialProductDO::getOpenDueFlag, reqVO.getOpenDueFlag())
                .betweenIfPresent(MaterialProductDO::getOpenDueAfter, reqVO.getOpenDueAfter())
                .eqIfPresent(MaterialProductDO::getHazardous, reqVO.getHazardous())
                .eqIfPresent(MaterialProductDO::getStandardSolutionFlag, reqVO.getStandardSolutionFlag())
                .eqIfPresent(MaterialProductDO::getStandardMaterialFlag, reqVO.getStandardMaterialFlag())
                .betweenIfPresent(MaterialProductDO::getReviewDue, reqVO.getReviewDue())
                .eqIfPresent(MaterialProductDO::getCancelFlag, reqVO.getCancelFlag())
                .eqIfPresent(MaterialProductDO::getAssayFlag, reqVO.getAssayFlag())
                .eqIfPresent(MaterialProductDO::getSystemDepartmentCode, reqVO.getSystemDepartmentCode())
                .eqIfPresent(MaterialProductDO::getRemark, reqVO.getRemark())
                .betweenIfPresent(MaterialProductDO::getCreateTime, reqVO.getCreateTime())
                ;
        // 使用 EXISTS 子查询过滤有指定部门或库位库存的产品
        if (CollUtil.isNotEmpty(reqVO.getDepartmentIds())) {
            String deptIdsStr = reqVO.getDepartmentIds().stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(","));
            wrapper.exists("SELECT 1 FROM t_mtrl_inf WHERE t_mtrl_inf.PDT_ID = t_mtrl_pdt.ID AND t_mtrl_inf.USG_STS <> 1 AND t_mtrl_inf.BLG_DEPT_ID IN (" + deptIdsStr + ")");
        }

        if (CollUtil.isNotEmpty(reqVO.getLocationIds())) {
            String locationIdsStr = reqVO.getLocationIds().stream()
                    .map(String::valueOf)
                    .collect(Collectors.joining(","));
            wrapper.exists("SELECT 1 FROM t_mtrl_inf WHERE t_mtrl_inf.PDT_ID = t_mtrl_pdt.ID AND t_mtrl_inf.USG_STS <> 1 AND t_mtrl_inf.LOC_ID IN (" + locationIdsStr + ")");
        }

        wrapper.orderByAsc(MaterialProductDO::getSortNo)
                .orderByAsc(MaterialProductDO::getIdPath)
                .orderByDesc(MaterialProductDO::getId);
        return selectPage(reqVO, wrapper);
    }

    default boolean checkIsExistsBatchByPdt(List<Long> ids){
        MPJLambdaWrapperX<MaterialProductDO> wrapperX = new MPJLambdaWrapperX<MaterialProductDO>()
                .innerJoin(MaterialBatchDO.class, MaterialBatchDO::getProductId, MaterialProductDO::getId)
                .in(MaterialProductDO::getId, ids);
        return this.exists(wrapperX);
    }

    default Map<Long, Long> getStockQuantityByPdtIds(List<Long> mtrlIds, Boolean dataPermissionByBlgDept) {
        MPJLambdaWrapper<MaterialProductDO> wrapper = new MPJLambdaWrapper<MaterialProductDO>()
                .select(MaterialProductDO::getId)
                .selectCount(MaterialInfomationDO::getId, "quantity")
                .leftJoin(MaterialInfomationDO.class, MaterialInfomationDO::getProductId, MaterialProductDO::getId)
                .in(MaterialProductDO::getId, mtrlIds)
                .ne(MaterialInfomationDO::getUsageStatus, 1)
                .in(dataPermissionByBlgDept && SecurityFrameworkUtils.getLoginUser() != null,
                        MaterialInfomationDO::getBelongDepartmentId, Objects.requireNonNull(SecurityFrameworkUtils.getLoginUser()).getVisitDeptId())
                .groupBy(MaterialProductDO::getId);

        List<Map<String, Object>> maps = selectJoinMaps(wrapper);
        if (CollUtil.isEmpty(maps)) return new HashMap<>();

        return maps.stream().collect(Collectors.toMap(
                map -> (Long) map.get("ID"),
                map -> (Long) map.get("QUANTITY")
        ));
    }

    default Map<Long, Long> getStockQuantityByPdtIds(List<Long> mtrlIds, List<Long> warehouseIds) {
        MPJLambdaWrapper<MaterialProductDO> wrapper = new MPJLambdaWrapper<MaterialProductDO>()
                .select(MaterialProductDO::getId)
                .selectCount(MaterialInfomationDO::getId, "quantity")
                .leftJoin(MaterialInfomationDO.class, MaterialInfomationDO::getProductId, MaterialProductDO::getId)
                .leftJoin(ConfigWarehouseLocationDO.class, "location", ConfigWarehouseLocationDO::getId, MaterialInfomationDO::getLocationId)
                .leftJoin(ConfigWarehouseLocationDO.class, "warehouse", ConfigWarehouseLocationDO::getId, "location", ConfigWarehouseLocationDO::getParentId)
                .in(MaterialProductDO::getId, mtrlIds)
                .ne(MaterialInfomationDO::getUsageStatus, 1)
                .in(CollUtil.isNotEmpty(warehouseIds), "warehouse.ID", warehouseIds)
                .groupBy(MaterialProductDO::getId);

        List<Map<String, Object>> maps = selectJoinMaps(wrapper);
        if (CollUtil.isEmpty(maps)) return new HashMap<>();

        return maps.stream().collect(Collectors.toMap(
                map -> (Long) map.get("ID"),
                map -> (Long) map.get("QUANTITY")
        ));
    }

    default boolean checkIsExistsSolutionByPdt(List<Long> ids) {
        MPJLambdaWrapperX<MaterialProductDO> wrapperXMakeApply = new MPJLambdaWrapperX<MaterialProductDO>()
                .innerJoin(MaterialLifecycleDetailDO.class, MaterialLifecycleDetailDO::getProductId, MaterialProductDO::getId)
                .in(MaterialProductDO::getId, ids);
        MPJLambdaWrapperX<MaterialProductDO> wrapperXMake = new MPJLambdaWrapperX<MaterialProductDO>()
                .innerJoin(MaterialInfomationDO.class, MaterialInfomationDO::getProductId, MaterialProductDO::getId)
                .innerJoin(MaterialStandardSolutionDO.class, MaterialStandardSolutionDO::getInfomationId, MaterialInfomationDO::getId)
                .in(MaterialProductDO::getId, ids);
        return this.exists(wrapperXMakeApply) || this.exists(wrapperXMake);
    }


    default boolean checkIsExistsInfByPdt(List<Long> pdtIds) {
        MPJLambdaWrapperX<MaterialProductDO> wrapperX = new MPJLambdaWrapperX<MaterialProductDO>()
                .innerJoin(MaterialInfomationDO.class, MaterialInfomationDO::getProductId, MaterialProductDO::getId)
                .in(MaterialProductDO::getId, pdtIds);
        return this.exists(wrapperX);
    }

    List<MaterialProductDO> selectListWithCustomSql(@Param("param") MaterialProductPageReqVO reqVO);
}