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

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
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.module.qms.business.config.dal.dataobject.ConfigWarehouseLocationDO;
import com.zt.plat.module.qms.core.aspect.annotation.QmsPermission;
import com.zt.plat.module.qms.enums.QmsPermissionConstant;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceConfigBusinessRuleDO;
import com.zt.plat.module.qms.resource.device.dal.dataobject.DeviceProductDO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialInfomationPageReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialInfomationRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.query.MaterialInfomationQueryVO;
import com.zt.plat.module.qms.resource.material.controller.vo.resp.MaterialInfomationLedgerRespVO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.*;
import com.zt.plat.module.qms.resource.material.enums.MaterialInfomationPageBusinessType;
import org.apache.ibatis.annotations.Mapper;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 物料实例 Mapper
 *
 * @author 后台管理
 */
@Mapper
public interface MaterialInfomationMapper extends BaseMapperX<MaterialInfomationDO> {

    default PageResult<MaterialInfomationDO> selectPage(MaterialInfomationPageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<MaterialInfomationDO>()
                .eqIfPresent(MaterialInfomationDO::getProductId, reqVO.getProductId())
                .eqIfPresent(MaterialInfomationDO::getBatchId, reqVO.getBatchId())
                .eqIfPresent(MaterialInfomationDO::getLocationId, reqVO.getLocationId())
                .eqIfPresent(MaterialInfomationDO::getCode, reqVO.getCode())
                .eqIfPresent(MaterialInfomationDO::getParameter, reqVO.getParameter())
                .eqIfPresent(MaterialInfomationDO::getPublishStatus, reqVO.getPublishStatus())
                .eqIfPresent(MaterialInfomationDO::getUsageStatus, reqVO.getUsageStatus())
                .eqIfPresent(MaterialInfomationDO::getManagerDepartmentId, reqVO.getManagerDepartmentId())
                .likeIfPresent(MaterialInfomationDO::getManagerDepartmentName, reqVO.getManagerDepartmentName())
                .eqIfPresent(MaterialInfomationDO::getManagerUserId, reqVO.getManagerUserId())
                .likeIfPresent(MaterialInfomationDO::getManagerUserName, reqVO.getManagerUserName())
                .eqIfPresent(MaterialInfomationDO::getOpenStatus, reqVO.getOpenStatus())
                .eqIfPresent(MaterialInfomationDO::getOpenUserId, reqVO.getOpenUserId())
                .likeIfPresent(MaterialInfomationDO::getOpenUserName, reqVO.getOpenUserName())
                .betweenIfPresent(MaterialInfomationDO::getOpenDate, reqVO.getOpenDate())
                .betweenIfPresent(MaterialInfomationDO::getExpirationDate, reqVO.getExpirationDate())
                .eqIfPresent(MaterialInfomationDO::getExpirationFlag, reqVO.getExpirationFlag())
                .eqIfPresent(MaterialInfomationDO::getRemainingVolume, reqVO.getRemainingVolume())
                .eqIfPresent(MaterialInfomationDO::getUseEndFlag, reqVO.getUseEndFlag())
                .eqIfPresent(MaterialInfomationDO::getSystemDepartmentCode, reqVO.getSystemDepartmentCode())
                .eqIfPresent(MaterialInfomationDO::getRemark, reqVO.getRemark())
                .betweenIfPresent(MaterialInfomationDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(MaterialInfomationDO::getId));
    }

    @QmsPermission(deptIdColumn = "BLG_DEPT_ID",
            moduleDataRoleCodes = QmsPermissionConstant.ADMIN_ROLE + "," + QmsPermissionConstant.MATERIAL_ADMIN_ROLE)
    default PageResult<MaterialInfomationRespVO> selectPageWithPdtInfo(MaterialInfomationPageReqVO reqVO) {
        MPJLambdaWrapper<MaterialInfomationDO> wrapper = new MPJLambdaWrapperX<MaterialInfomationDO>()
                .select(MaterialInfomationDO::getId,
                        MaterialInfomationDO::getProductId, MaterialInfomationDO::getBatchId, MaterialInfomationDO::getGongduanId,
                        MaterialInfomationDO::getCode, MaterialInfomationDO::getOrigin, MaterialInfomationDO::getPublishStatus,
                        MaterialInfomationDO::getUsageStatus, MaterialInfomationDO::getManagerDepartmentId,
                        MaterialInfomationDO::getManagerDepartmentName, MaterialInfomationDO::getManagerUserId, MaterialInfomationDO::getManagerUserName,
                        MaterialInfomationDO::getOpenStatus, MaterialInfomationDO::getOpenUserId, MaterialInfomationDO::getOpenUserName,
                        MaterialInfomationDO::getOpenDate, MaterialInfomationDO::getExpirationDate, MaterialInfomationDO::getManufacturerDate,
                        MaterialInfomationDO::getExpirationFlag, MaterialInfomationDO::getRemainingVolume, MaterialInfomationDO::getUseEndFlag,
                        MaterialInfomationDO::getSystemDepartmentCode, MaterialInfomationDO::getRemark,
                        MaterialInfomationDO::getCreateTime, MaterialInfomationDO::getUpdateTime)
                .select(MaterialProductDO::getName, MaterialProductDO::getSpecification, MaterialProductDO::getStandardCapacity,
                        MaterialProductDO::getModelNo, MaterialProductDO::getParameter, MaterialProductDO::getManufacturer,
                        MaterialProductDO::getUnit, MaterialProductDO::getDue,
                        MaterialProductDO::getHazardous, MaterialProductDO::getStandardMaterialFlag, MaterialProductDO::getStandardSolutionFlag)
                .select(MaterialStandardSolutionDO::getConcentration, MaterialStandardSolutionDO::getTiter,
                        MaterialStandardSolutionDO::getMakeUserId, MaterialStandardSolutionDO::getMakeUser,
                        MaterialStandardSolutionDO::getMakeDate)
                .selectAs("batch.BAT_NO", MaterialInfomationRespVO::getBatchNo)
                .selectAs("gongduan.ASN_DEPT_NAME", MaterialInfomationRespVO::getAssignDepartmentName)
                .selectAs(ConfigWarehouseLocationDO::getCode, MaterialInfomationRespVO::getLocationCode)
                .leftJoin(MaterialProductDO.class, MaterialProductDO::getId, MaterialInfomationDO::getProductId)
                .leftJoin(MaterialBatchDO.class, "batch", MaterialBatchDO::getId, MaterialInfomationDO::getBatchId)
                .leftJoin(MaterialBatchDO.class, "gongduan", MaterialBatchDO::getId, MaterialInfomationDO::getGongduanId)
                .leftJoin(ConfigWarehouseLocationDO.class, ConfigWarehouseLocationDO::getId, MaterialInfomationDO::getLocationId)
                .leftJoin(MaterialStandardSolutionDO.class, MaterialStandardSolutionDO::getInfomationId, MaterialInfomationDO::getId)
                .eqIfExists(MaterialInfomationDO::getProductId, reqVO.getProductId())
                .eqIfExists(MaterialInfomationDO::getBatchId, reqVO.getBatchId())
                .eqIfExists(MaterialInfomationDO::getLocationId, reqVO.getLocationId())
                .eqIfExists(MaterialInfomationDO::getCode, reqVO.getCode())
                .eqIfExists(MaterialProductDO::getStandardMaterialFlag, reqVO.getStandardMaterialFlag())
                .eqIfExists(MaterialProductDO::getStandardSolutionFlag, reqVO.getStandardSolutionFlag())
                .eqIfExists(MaterialProductDO::getHazardous, reqVO.getHazardous())
                .eqIfExists(MaterialProductDO::getParameter, reqVO.getParameter())
                .eqIfExists(MaterialInfomationDO::getPublishStatus, reqVO.getPublishStatus())
                .eqIfExists(MaterialInfomationDO::getUsageStatus, reqVO.getUsageStatus())
                //.eqIfExists(MaterialInfomationDO::getManagerDepartmentId, reqVO.getManagerDepartmentId())
                .likeIfExists(MaterialProductDO::getName, reqVO.getName())
                //.likeIfExists(MaterialInfomationDO::getManagerDepartmentName, reqVO.getManagerDepartmentName())
                .eqIfExists(MaterialInfomationDO::getManagerUserId, reqVO.getManagerUserId())
                .likeIfExists(MaterialInfomationDO::getManagerUserName, reqVO.getManagerUserName())
                .eqIfExists(MaterialInfomationDO::getOpenStatus, reqVO.getOpenStatus())
                .eqIfExists(MaterialInfomationDO::getOpenUserId, reqVO.getOpenUserId())
                .likeIfExists(MaterialInfomationDO::getOpenUserName, reqVO.getOpenUserName())
                .eqIfExists(MaterialInfomationDO::getExpirationFlag, reqVO.getExpirationFlag())
                .eqIfExists(MaterialInfomationDO::getUseEndFlag, reqVO.getUseEndFlag())
                // .eqIfExists(MaterialInfomationDO::getSystemDepartmentCode, reqVO.getSystemDepartmentCode())
                .likeIfExists(MaterialInfomationDO::getRemark, reqVO.getRemark())
                .orderByDesc(MaterialInfomationDO::getId);
        return selectJoinPage(reqVO, MaterialInfomationRespVO.class, wrapper);
    }

    default MaterialInfomationRespVO selectOneWithPdtInfoByInfCode(MaterialInfomationQueryVO queryVO){
        MPJLambdaWrapper<MaterialInfomationDO> wrapper = getInfomationDOMPJLambdaWrapper();
        wrapper.eqIfExists(MaterialInfomationDO::getCode, queryVO.getCode())
                .eqIfExists(MaterialInfomationDO::getUsageStatus, queryVO.getUsageStatus())
                .eqIfExists(MaterialInfomationDO::getUseEndFlag, queryVO.getUseEndFlag())
                .eqIfExists(MaterialProductDO::getHazardous, queryVO.getHazardous())
                .eqIfExists(MaterialProductDO::getStandardMaterialFlag, queryVO.getStandardMaterialFlag())
                .eqIfExists(MaterialProductDO::getStandardSolutionFlag, queryVO.getStandardSolutionFlag())
                .eqIfExists(MaterialProductDO::getOpenDueFlag, queryVO.getOpenDueFlag())
                .eqIfExists(MaterialInfomationDO::getOpenStatus, queryVO.getOpenStatus());
        return selectJoinOne(MaterialInfomationRespVO.class, wrapper);
    }

    default MPJLambdaWrapper<MaterialInfomationDO> getInfomationDOMPJLambdaWrapper() {
        return new MPJLambdaWrapperX<MaterialInfomationDO>()
                .select(MaterialInfomationDO::getId,
                        MaterialInfomationDO::getProductId, MaterialInfomationDO::getBatchId, MaterialInfomationDO::getGongduanId,
                        MaterialInfomationDO::getCode, MaterialInfomationDO::getOrigin, MaterialInfomationDO::getPublishStatus,
                        MaterialInfomationDO::getUsageStatus, MaterialInfomationDO::getManagerDepartmentId,
                        MaterialInfomationDO::getManagerDepartmentName, MaterialInfomationDO::getManagerUserId, MaterialInfomationDO::getManagerUserName,
                        MaterialInfomationDO::getOpenStatus, MaterialInfomationDO::getOpenUserId, MaterialInfomationDO::getOpenUserName,
                        MaterialInfomationDO::getOpenDate, MaterialInfomationDO::getExpirationDate, MaterialInfomationDO::getManufacturerDate,
                        MaterialInfomationDO::getExpirationFlag, MaterialInfomationDO::getRemainingVolume, MaterialInfomationDO::getUseEndFlag,
                        MaterialInfomationDO::getInitialVolume, MaterialInfomationDO::getSystemDepartmentCode, MaterialInfomationDO::getRemark,
                        MaterialInfomationDO::getCreateTime, MaterialInfomationDO::getUpdateTime)
                .select(MaterialProductDO::getName, MaterialProductDO::getSpecification, MaterialProductDO::getStandardCapacity,
                        MaterialProductDO::getModelNo, MaterialProductDO::getParameter, MaterialProductDO::getManufacturer,
                        MaterialProductDO::getUnit, MaterialProductDO::getDue,
                        MaterialProductDO::getHazardous, MaterialProductDO::getStandardMaterialFlag, MaterialProductDO::getStandardSolutionFlag)
                .select(MaterialStandardSolutionDO::getConcentration, MaterialStandardSolutionDO::getTiter,
                        MaterialStandardSolutionDO::getMakeUserId, MaterialStandardSolutionDO::getMakeUser,
                        MaterialStandardSolutionDO::getMakeDate)
                .selectAs("batch.BAT_NO", MaterialInfomationRespVO::getBatchNo)
                .selectAs("gongduan.ASN_DEPT_NAME", MaterialInfomationRespVO::getAssignDepartmentName)
                .selectAs(ConfigWarehouseLocationDO::getCode, MaterialInfomationRespVO::getLocationCode)
                .innerJoin(MaterialProductDO.class, MaterialProductDO::getId, MaterialInfomationDO::getProductId)
                .leftJoin(MaterialBatchDO.class, "batch", MaterialBatchDO::getId, MaterialInfomationDO::getBatchId)
                .leftJoin(MaterialBatchDO.class, "gongduan", MaterialBatchDO::getId, MaterialInfomationDO::getGongduanId)
                .leftJoin(ConfigWarehouseLocationDO.class, ConfigWarehouseLocationDO::getId, MaterialInfomationDO::getLocationId)
                .leftJoin(MaterialStandardSolutionDO.class, MaterialStandardSolutionDO::getInfomationId, MaterialInfomationDO::getId);
    }

    default MaterialInfomationRespVO selectOneWithPdtInfoByInfId(Long id) {
        MPJLambdaWrapper<MaterialInfomationDO> wrapper = getInfomationDOMPJLambdaWrapper();
        wrapper.eqIfExists(MaterialInfomationDO::getId, id);
        return selectJoinOne(MaterialInfomationRespVO.class, wrapper);
    }

    default List<MaterialInfomationRespVO> selectListWithPdtInfoByInfIds(List<Long> ids) {
        MPJLambdaWrapper<MaterialInfomationDO> wrapper = getInfomationDOMPJLambdaWrapper();
        wrapper.in(MaterialInfomationDO::getId, ids);
        return selectJoinList(MaterialInfomationRespVO.class, wrapper);
    }

    default Map<Long, Boolean> checkIsExistHazardousMakeInfo(List<Long> infIds) {
        // 查询作为源物料的配置记录数量
        MPJLambdaWrapper<MaterialInfomationDO> wrapper1 = new MPJLambdaWrapper<MaterialInfomationDO>()
                .select(MaterialInfomationDO::getId)
                .selectCount(MaterialUseRecordDetailDO::getId, "count")
                .leftJoin(MaterialUseRecordDetailDO.class,
                        MaterialUseRecordDetailDO::getInfomationId,
                        MaterialInfomationDO::getId)
                .in(MaterialInfomationDO::getId, infIds)
                .groupBy(MaterialInfomationDO::getId);

        // 查询作为目标物料的配置记录数量
        MPJLambdaWrapper<MaterialInfomationDO> wrapper2 = new MPJLambdaWrapper<MaterialInfomationDO>()
                .select(MaterialInfomationDO::getId)
                .selectCount(MaterialUseRecordDetailDO::getId, "count")
                .leftJoin(MaterialUseRecordDetailDO.class,
                        MaterialUseRecordDetailDO::getTargetInfomationId,
                        MaterialInfomationDO::getId)
                .in(MaterialInfomationDO::getId, infIds)
                .groupBy(MaterialInfomationDO::getId);

        List<Map<String, Object>> result1 = selectJoinMaps(wrapper1);
        List<Map<String, Object>> result2 = selectJoinMaps(wrapper2);

        // 合并两个查询结果
        Map<Long, Long> totalCountMap = new HashMap<>();

        // 处理第一组结果（作为源物料）
        for (Map<String, Object> row : result1) {
            Long infId = ((Number) row.get("ID")).longValue();
            Long count = ((Number) row.get("COUNT")).longValue();
            totalCountMap.put(infId, count);
        }

        // 处理第二组结果（作为目标物料），累加到总计数中
        for (Map<String, Object> row : result2) {
            Long infId = ((Number) row.get("ID")).longValue();
            Long count = ((Number) row.get("COUNT")).longValue();
            totalCountMap.merge(infId, count, Long::sum);
        }

        // 构建最终结果
        Map<Long, Boolean> resultMap = new HashMap<>();
        for (Long infId : infIds) {
            Long totalCount = totalCountMap.getOrDefault(infId, 0L);
            resultMap.put(infId, totalCount > 0);
        }

        return resultMap;
    }

    default List<MaterialInfoWithBizConfigVO> getListNeedByRule(JSONObject param){
        String businessType = param.getString("businessType");
        Long infoId = param.getLong("infoId");
        List deptIdList = param.getJSONArray("deptIdList");
        MPJLambdaWrapperX<MaterialInfomationDO> wrapper = new MPJLambdaWrapperX<>();
        wrapper.leftJoin(DeviceProductDO.class, DeviceProductDO::getId, MaterialInfomationDO::getProductId)
                .leftJoin(DeviceProductDO.class, DeviceProductDO::getId, MaterialInfomationDO::getProductId)
                .selectAssociation(DeviceConfigBusinessRuleDO.class, MaterialInfoWithBizConfigVO::getRule)
                .leftJoin(DeviceConfigBusinessRuleDO.class, DeviceConfigBusinessRuleDO::getProductId, MaterialInfomationDO::getProductId)
                .selectAll(MaterialInfomationDO.class);
        wrapper.eqIfPresent(MaterialInfomationDO::getId, infoId)
                .inIfPresent(MaterialInfomationDO::getDeptId, deptIdList)
                .eq(DeviceConfigBusinessRuleDO::getBusinessDomain, businessType)
                .eq(DeviceConfigBusinessRuleDO::getRequireFlag, "1");

        return selectJoinList(MaterialInfoWithBizConfigVO.class, wrapper);
    }

    @QmsPermission(deptIdColumn = "BLG_DEPT_ID",
            moduleDataRoleCodes = QmsPermissionConstant.ADMIN_ROLE + "," + QmsPermissionConstant.MATERIAL_ADMIN_ROLE)
    default PageResult<MaterialInfomationLedgerRespVO> selectInventoryLedgerPage(MaterialInfomationPageReqVO reqVO) {
        MPJLambdaWrapper<MaterialInfomationDO> wrapper = new MPJLambdaWrapperX<MaterialInfomationDO>()
                .select(MaterialInfomationDO::getProductId)
                .selectAs(MaterialInfomationDO::getBelongDepartmentId, MaterialInfomationLedgerRespVO::getDepartmentId)
                .select(MaterialInfomationDO::getLocationId)
                .selectCount(MaterialInfomationDO::getId, MaterialInfomationLedgerRespVO::getDepartmentInventoryQuantity)
                .innerJoin(MaterialProductDO.class, MaterialProductDO::getId, MaterialInfomationDO::getProductId)
                .eqIfExists(MaterialProductDO::getHazardous, reqVO.getHazardous())
                .eq(MaterialInfomationDO::getUsageStatus, 0)
                .likeIfExists(MaterialProductDO::getName, reqVO.getName())
                .groupBy(MaterialInfomationDO::getProductId,
                        MaterialInfomationDO::getBelongDepartmentId,
                        MaterialInfomationDO::getLocationId);

        return selectJoinPage(reqVO, MaterialInfomationLedgerRespVO.class, wrapper);
    }
}