package com.zt.plat.module.base.service.materialproperties;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

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

import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.base.controller.admin.materialproperties.vo.MaterialPropertiesPageReqVO;
import com.zt.plat.module.base.controller.admin.materialproperties.vo.MaterialPropertiesRespVO;
import com.zt.plat.module.base.controller.admin.materialproperties.vo.MaterialPropertiesSaveReqVO;
import com.zt.plat.module.base.controller.admin.materialproperties.vo.MaterialPropertiesSimplePageReqVO;
import com.zt.plat.module.base.controller.admin.materialproperties.vo.MaterialPropertiesSimpleRespVO;
import com.zt.plat.module.base.dal.dao.materialproperties.MaterialPropertiesMapper;
import com.zt.plat.module.base.dal.dao.quantityUnitRelation.QuantityUnitRelationMapper;
import com.zt.plat.module.base.dal.dao.unitQuantity.UnitQuantityMapper;
import com.zt.plat.module.base.dal.dao.untInfo.UntInfoMapper;
import com.zt.plat.module.base.dal.dao.businessdictionarytype.BusinessDictionaryDataMapper;
import com.zt.plat.module.base.dal.dataobject.materialproperties.MaterialPropertiesDO;
import com.zt.plat.module.base.dal.dataobject.quantityUnitRelation.QuantityUnitRelationDO;
import com.zt.plat.module.base.dal.dataobject.unitQuantity.UnitQuantityDO;
import com.zt.plat.module.base.dal.dataobject.untInfo.UntInfoDO;
import com.zt.plat.module.base.dal.dataobject.businessdictionarytype.BusinessDictionaryDataDO;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.base.enums.ErrorCodeConstants.MATERIAL_PROPERTIES_NOT_EXISTS;

/**
 * 物料属性 Service 实现类
 */
@Service
@Validated
public class MaterialPropertiesServiceImpl implements MaterialPropertiesService {

    @Resource
    private MaterialPropertiesMapper materialPropertiesMapper;

    @Resource
    private QuantityUnitRelationMapper quantityUnitRelationMapper;

    @Resource
    private UnitQuantityMapper unitQuantityMapper;

    @Resource
    private UntInfoMapper untInfoMapper;

    @Resource
    private BusinessDictionaryDataMapper businessDictionaryDataMapper;

    @Override
    public MaterialPropertiesRespVO createMaterialProperties(MaterialPropertiesSaveReqVO createReqVO) {
        MaterialPropertiesDO materialProperties = BeanUtils.toBean(createReqVO, MaterialPropertiesDO.class);
        materialPropertiesMapper.insert(materialProperties);
        return CollUtil.getFirst(buildRespList(Collections.singletonList(materialProperties)));
    }

    @Override
    public void updateMaterialProperties(MaterialPropertiesSaveReqVO updateReqVO) {
        validateMaterialPropertiesExists(updateReqVO.getId());
        MaterialPropertiesDO updateObj = BeanUtils.toBean(updateReqVO, MaterialPropertiesDO.class);
        materialPropertiesMapper.updateById(updateObj);
    }

    @Override
    public void deleteMaterialProperties(Long id) {
        validateMaterialPropertiesExists(id);
        materialPropertiesMapper.deleteById(id);
    }

    @Override
    public void deleteMaterialPropertiesListByIds(List<Long> ids) {
        validateMaterialPropertiesExists(ids);
        materialPropertiesMapper.deleteByIds(ids);
    }

    private void validateMaterialPropertiesExists(List<Long> ids) {
        List<MaterialPropertiesDO> list = materialPropertiesMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_PROPERTIES_NOT_EXISTS);
        }
    }

    private void validateMaterialPropertiesExists(Long id) {
        if (materialPropertiesMapper.selectById(id) == null) {
            throw exception(MATERIAL_PROPERTIES_NOT_EXISTS);
        }
    }

    @Override
    public MaterialPropertiesRespVO getMaterialProperties(Long id) {
        MaterialPropertiesDO entity = materialPropertiesMapper.selectById(id);
        if (entity == null) {
            return null;
        }
        return CollUtil.getFirst(buildRespList(Collections.singletonList(entity)));
    }

    @Override
    public PageResult<MaterialPropertiesRespVO> getMaterialPropertiesPage(MaterialPropertiesPageReqVO pageReqVO) {
        PageResult<MaterialPropertiesDO> pageResult = materialPropertiesMapper.selectPage(pageReqVO);
        List<MaterialPropertiesRespVO> respList = buildRespList(pageResult.getList());
        return new PageResult<>(respList, pageResult.getTotal());
    }

    @Override
    public PageResult<MaterialPropertiesSimpleRespVO> getMaterialPropertiesSimplePage(MaterialPropertiesSimplePageReqVO pageReqVO) {
        PageResult<MaterialPropertiesDO> pageResult = materialPropertiesMapper.selectSimplePage(pageReqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return new PageResult<>(Collections.emptyList(), pageResult.getTotal());
        }
        List<MaterialPropertiesRespVO> respList = buildRespList(pageResult.getList());
        List<MaterialPropertiesSimpleRespVO> simpleList = buildSimpleList(respList);
        return new PageResult<>(simpleList, pageResult.getTotal());
    }

    private List<MaterialPropertiesSimpleRespVO> buildSimpleList(List<MaterialPropertiesRespVO> respList) {
        if (CollUtil.isEmpty(respList)) {
            return Collections.emptyList();
        }
        return respList.stream().map(item -> {
            MaterialPropertiesSimpleRespVO vo = new MaterialPropertiesSimpleRespVO();
            vo.setId(item.getId());
            vo.setCode(item.getCode());
            vo.setName(item.getName());
            vo.setDataType(item.getDataType());
            vo.setUnitName(item.getUnitName());
            vo.setUnitSymbol(item.getUnitSymbol());
            vo.setDictionaryDataValue(item.getDictionaryDataValue());
            vo.setDictionaryDataLabel(item.getDictionaryDataLabel());
            return vo;
        }).collect(Collectors.toList());
    }

    private List<MaterialPropertiesRespVO> buildRespList(List<MaterialPropertiesDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }

        Set<Long> relationIds = list.stream()
                .map(MaterialPropertiesDO::getUnitQuantityId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        Map<Long, QuantityUnitRelationDO> relationMap = relationIds.isEmpty()
                ? Collections.emptyMap()
                : quantityUnitRelationMapper.selectBatchIds(relationIds).stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toMap(QuantityUnitRelationDO::getId, Function.identity()));

        Set<Long> quantityIds = relationMap.values().stream()
                .map(QuantityUnitRelationDO::getUntQtyId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        Set<Long> unitIds = relationMap.values().stream()
                .map(QuantityUnitRelationDO::getUntId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        Map<Long, UnitQuantityDO> quantityMap = quantityIds.isEmpty()
                ? Collections.emptyMap()
                : unitQuantityMapper.selectBatchIds(quantityIds).stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toMap(UnitQuantityDO::getId, Function.identity()));

        Map<Long, UntInfoDO> unitMap = unitIds.isEmpty()
                ? Collections.emptyMap()
                : untInfoMapper.selectBatchIds(unitIds).stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toMap(UntInfoDO::getId, Function.identity()));

    Set<String> dictionaryValues = list.stream()
        .map(MaterialPropertiesDO::getDictionaryDataValue)
        .filter(StrUtil::isNotBlank)
        .collect(Collectors.toSet());

    Map<String, BusinessDictionaryDataDO> dictionaryMap = dictionaryValues.isEmpty()
        ? Collections.emptyMap()
        : businessDictionaryDataMapper.selectListByValues(dictionaryValues).stream()
                    .filter(Objects::nonNull)
                    .collect(Collectors.toMap(BusinessDictionaryDataDO::getValue, Function.identity(), (existing, replacement) -> existing));

        return list.stream().map(item -> {
            MaterialPropertiesRespVO respVO = BeanUtils.toBean(item, MaterialPropertiesRespVO.class);

            QuantityUnitRelationDO relation = relationMap.get(item.getUnitQuantityId());
            if (relation != null) {
                UnitQuantityDO quantity = quantityMap.get(relation.getUntQtyId());
                if (quantity != null) {
                    respVO.setUnitQuantityName(quantity.getName());
                }
                UntInfoDO unit = unitMap.get(relation.getUntId());
                if (unit != null) {
                    respVO.setUnitName(unit.getName());
                    respVO.setUnitSymbol(unit.getSmb());
                }
            }

            BusinessDictionaryDataDO dictionaryDataDO = dictionaryMap.get(item.getDictionaryDataValue());
            if (dictionaryDataDO != null) {
                respVO.setDictionaryDataLabel(dictionaryDataDO.getLabel());
            } else {
                respVO.setDictionaryDataLabel(respVO.getDictionaryDataValue());
            }

            return respVO;
        }).collect(Collectors.toList());
    }
}