package org.dromara.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.*;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.domain.asset.AssetType;
import org.dromara.domain.asset.bo.AssetTypeBo;
import org.dromara.domain.asset.vo.AssetTypeVo;
import org.dromara.mapper.AssetTypeMapper;
import org.dromara.service.IAssetTypeService;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;
import java.util.Map;

import static org.dromara.common.core.constant.Constants.SUCCESS;

/**
 * 资产类型Service业务层处理
 *
 * @author boman
 * @date 2025-04-11
 */
@RequiredArgsConstructor
@Service
public class AssetTypeServiceImpl implements IAssetTypeService {

    private final AssetTypeMapper baseMapper;

    /**
     * 查询资产类型
     *
     * @param assetId 主键
     * @return 资产类型
     */
    @Override
    public AssetTypeVo queryById(Long assetId){
        return baseMapper.selectVoById(assetId);
    }

    /**
     * 分页查询资产类型列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 资产类型分页列表
     */
    @Override
    public TableDataInfo<AssetTypeVo> queryPageList(AssetTypeBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<AssetType> lqw = buildQueryWrapper(bo);
        Page<AssetTypeVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的资产类型列表
     *
     * @param bo 查询条件
     * @return 资产类型列表
     */
    @Override
    public List<AssetTypeVo> queryList(AssetTypeBo bo) {
        LambdaQueryWrapper<AssetType> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<AssetType> buildQueryWrapper(AssetTypeBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<AssetType> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(AssetType::getAssetId);
        lqw.eq(bo.getParentId() != null, AssetType::getParentId, bo.getParentId());
        lqw.eq(StringUtils.isNotBlank(bo.getAncestors()), AssetType::getAncestors, bo.getAncestors());
        lqw.like(StringUtils.isNotBlank(bo.getAssetName()), AssetType::getAssetName, bo.getAssetName());
        lqw.eq(bo.getOrderNum() != null, AssetType::getOrderNum, bo.getOrderNum());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), AssetType::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增资产类型
     *
     * @param bo 资产类型
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(AssetTypeBo bo) {
        bo.setCreateTime(DateUtils.getNowDate());
        AssetTypeVo info = baseMapper.selectAssetTypeByAssetId(bo.getParentId());
        int i = 0;
        if (info != null) {
            // 如果父节点不为正常状态,则不允许新增子节点
            // 如果父节点不为正常状态,则不允许新增子节点
            if (!SUCCESS.equals(info.getStatus())) {
                throw new ServiceException("部门停用，不允许新增");
            }
            bo.setAncestors(info.getAncestors() + "," + bo.getParentId());
            bo.setCreateTime(DateUtils.getNowDate());
        } else {
            bo.setParentId(0L);
            bo.setAncestors("0");
            bo.setCreateTime(DateUtils.getNowDate());
        }

        AssetType add = MapstructUtils.convert(bo, AssetType.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setAssetId(add.getAssetId());
        }
        return flag;
    }

    /**
     * 修改资产类型
     *
     * @param bo 资产类型
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(AssetTypeBo bo) {
        AssetTypeVo newParentAssetType = baseMapper.selectAssetTypeByAssetId(bo.getParentId());
        AssetTypeVo oldParentAssetType = baseMapper.selectAssetTypeByAssetId(bo.getAssetId());
        if (StringUtils.isNotNull(newParentAssetType) && StringUtils.isNotNull(oldParentAssetType)) {
            String newAncestors = newParentAssetType.getAncestors() + "," + newParentAssetType.getAncestors();
            String oldAncestors = oldParentAssetType.getAncestors();
            bo.setAncestors(newAncestors);
            updateAssetTypeChildren(bo.getAssetId(), newAncestors, oldAncestors);
        }
        bo.setUpdateTime(DateUtils.getNowDate());
        AssetType update = MapstructUtils.convert(bo, AssetType.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 修改子元素关系
     *
     * @param assetId      被修改的资产ID
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    public void updateAssetTypeChildren(Long assetId, String newAncestors, String oldAncestors) {
        List<AssetTypeVo> children = baseMapper.selectChildrenAssetTypeById(assetId);
        for (AssetTypeVo child : children) {
            child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
        }
        if (children.size() > 0) {
            baseMapper.updateAssetTypeChildren(children);
        }
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(AssetType entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除资产类型信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Override
    public R<List<Tree<Long>>> selectAssetTypeTreeList(AssetTypeBo bo) {
        LambdaQueryWrapper<AssetType> lqw = buildQueryWrapper(bo);
        List<AssetTypeVo> assetTypes = baseMapper.selectVoList(lqw);
        List<Tree<Long>> assetTypeTree = buildDeptTreeSelect(assetTypes);
        return R.ok(assetTypeTree);
    }

    /**
     * 检验资产名称的唯一性
     *
     * @param bo
     * @return
     */
    @Override
    public boolean checkAssetTypeNameUnique(AssetTypeBo bo) {

        Long assetId = StringUtils.isNull(bo.getAssetId()) ? -1L : bo.getAssetId();
        AssetTypeVo info = baseMapper.checkAssetNameUnique(bo.getAssetName(), bo.getParentId());
        if (StringUtils.isNotNull(info) && info.getAssetId().longValue() != assetId.longValue()) {
            return false;
        }
        return true;
    }

    @Override
    public int selectNormalChildrenAssetById(Long assetId) {
        return baseMapper.selectNormalChildrenAssetById(assetId);
    }

    /**
     * 是否存在子节点
     *
     * @param assetId 资产ID
     * @return 结果
     */
    @Override
    public boolean hasChildByAssetId(Long assetId) {
        int result = baseMapper.hasChildByAssetId(assetId);
        return result > 0;
    }

    private List<Tree<Long>> buildDeptTreeSelect(List<AssetTypeVo> assetTypes) {
        if (CollUtil.isEmpty(assetTypes)) {
            return CollUtil.newArrayList();
        }
        // 获取当前列表中每一个节点的parentId，然后在列表中查找是否有id与其parentId对应，若无对应，则表明此时节点列表中，该节点在当前列表中属于顶级节点
        List<Tree<Long>> treeList = CollUtil.newArrayList();
        for (AssetTypeVo d : assetTypes) {
            Long parentId = d.getParentId();
            AssetTypeVo assetTypeVo = StreamUtils.findFirst(assetTypes, it -> it.getAssetId().longValue() == parentId);
            if (ObjectUtil.isNull(assetTypeVo)) {
                List<Tree<Long>> trees = TreeBuildUtils.build(assetTypes, parentId, (assetType, tree) ->
                    tree.setId(assetType.getAssetId())
                        .setParentId(assetType.getParentId())
                        .setName(assetType.getAssetName())
                        .setWeight(assetType.getOrderNum())
                        .putExtra("disabled", SystemConstants.DISABLE.equals(assetType.getStatus())));
                Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getAssetId());
                treeList.add(tree);
            }
        }
        return treeList;
    }

}
