package org.dromara.rfid.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.rfid.domain.RfidLocation;
import org.dromara.rfid.domain.bo.RfidLocationBo;
import org.dromara.rfid.domain.vo.RfidLocationVo;
import org.dromara.rfid.mapper.RfidLocationMapper;
import org.dromara.rfid.service.IRfidLocationService;
import org.springframework.stereotype.Service;

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

/**
 * 位置信息Service业务层处理
 *
 * @author zch
 * @date 2025-11-25
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class RfidLocationServiceImpl implements IRfidLocationService {

    private final RfidLocationMapper baseMapper;

    /**
     * 查询位置信息
     *
     * @param id 主键
     * @return 位置信息
     */
    @Override
    public RfidLocationVo queryById(Long id){
        return baseMapper.selectCustomRfidLocationVoById(id);
    }


    /**
     * 查询符合条件的位置信息列表
     *
     * @param bo 查询条件
     * @return 位置信息列表
     */
    @Override
    public List<RfidLocationVo> queryList(RfidLocationBo bo) {
        LambdaQueryWrapper<RfidLocation> lqw = buildQueryWrapper(bo);
        // 使用自定义 Mapper XML + MyBatis-Plus Wrapper 查询列表
        return baseMapper.selectCustomRfidLocationVoList(lqw);
    }

    private LambdaQueryWrapper<RfidLocation> buildQueryWrapper(RfidLocationBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<RfidLocation> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(RfidLocation::getId);
        lqw.eq(StringUtils.isNotBlank(bo.getLocationCode()), RfidLocation::getLocationCode, bo.getLocationCode());
        lqw.eq(StringUtils.isNotBlank(bo.getLocationAlias()), RfidLocation::getLocationAlias, bo.getLocationAlias());
        lqw.eq(StringUtils.isNotBlank(bo.getLocationType()), RfidLocation::getLocationType, bo.getLocationType());
        lqw.eq(bo.getParentId() != null, RfidLocation::getParentId, bo.getParentId());
        lqw.eq(StringUtils.isNotBlank(bo.getIsMarked()), RfidLocation::getIsMarked, bo.getIsMarked());
        lqw.eq(StringUtils.isNotBlank(bo.getCreatedBy()), RfidLocation::getCreatedBy, bo.getCreatedBy());
        lqw.eq(bo.getCreatedAt() != null, RfidLocation::getCreatedAt, bo.getCreatedAt());
        lqw.eq(StringUtils.isNotBlank(bo.getUpdatedBy()), RfidLocation::getUpdatedBy, bo.getUpdatedBy());
        lqw.eq(bo.getUpdatedAt() != null, RfidLocation::getUpdatedAt, bo.getUpdatedAt());
        return lqw;
    }

    /**
     * 新增位置信息
     *
     * @param bo 位置信息
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(RfidLocationBo bo) {
        RfidLocation add = MapstructUtils.convert(bo, RfidLocation.class);
        validEntityBeforeSave(add);
        if (add.getParentId() == null || add.getParentId() == 0) {
            add.setParentId(0L);
            add.setAncestors("0");
        } else {
            RfidLocation parent = baseMapper.selectById(add.getParentId());
            if (parent == null) {
                throw new ServiceException("父位置不存在");
            }
            String ancestors = parent.getAncestors();
            if (StringUtils.isBlank(ancestors)) {
                ancestors = "0";
            }
            add.setAncestors(ancestors + "," + add.getParentId());
        }
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改位置信息
     *
     * @param bo 位置信息
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(RfidLocationBo bo) {
        RfidLocation update = MapstructUtils.convert(bo, RfidLocation.class);
        validEntityBeforeSave(update);

        RfidLocation oldLocation = baseMapper.selectById(update.getId());
        if (oldLocation == null) {
            return false;
        }

        if (update.getParentId() == null) {
            update.setParentId(0L);
        }

        // 父节点发生变化
        if (!update.getParentId().equals(oldLocation.getParentId())) {
            if (update.getParentId().equals(update.getId())) {
                throw new ServiceException("不能设置自己为父节点");
            }
            String newAncestors;
            if (update.getParentId() == 0) {
                newAncestors = "0";
            } else {
                RfidLocation parent = baseMapper.selectById(update.getParentId());
                if (parent == null) {
                    throw new ServiceException("父位置不存在");
                }
                String ancestors = parent.getAncestors();
                if (StringUtils.isBlank(ancestors)) {
                    ancestors = "0";
                }

                // 校验是否设置自己的子节点为父节点（即新父节点在当前节点子树中）
                String[] ancestorArr = ancestors.split(",");
                String currentIdStr = update.getId() == null ? null : update.getId().toString();
                if (currentIdStr != null) {
                    for (String ancestorId : ancestorArr) {
                        if (currentIdStr.equals(ancestorId)) {
                            throw new ServiceException("不能设置自己的子节点为父节点");
                        }
                    }
                }

                newAncestors = ancestors + "," + update.getParentId();
            }
            update.setAncestors(newAncestors);

            // 更新所有子节点的ancestors
            updateChildrenAncestors(update.getId(), newAncestors, oldLocation.getAncestors());
        } else {
            // 父节点未变化，保持原ancestors (防止前端传空)
            update.setAncestors(oldLocation.getAncestors());
        }

        return baseMapper.updateById(update) > 0;
    }

    /**
     * 递归更新所有子节点的ancestors
     */
    private void updateChildrenAncestors(Long currentId, String newAncestors, String oldAncestors) {
        // 查出所有以旧ancestors开头且包含当前id的子节点 (简单起见，这里仅演示逻辑，实际海量数据需优化)
        // RuoYi标准做法通常是查出所有children，然后替换前缀
        // 这里使用数据库函数或全量更新
        // 也可以查出所有直属子节点递归更新

        List<RfidLocation> children = baseMapper.selectList(new LambdaQueryWrapper<RfidLocation>()
            .apply("find_in_set({0}, ancestors)", currentId));

        for (RfidLocation child : children) {
             child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
             baseMapper.updateById(child);
        }
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(RfidLocation entity){
        // 校验位置编号唯一
        if (StringUtils.isNotBlank(entity.getLocationCode())) {
             boolean exists = baseMapper.exists(new LambdaQueryWrapper<RfidLocation>()
                .eq(RfidLocation::getLocationCode, entity.getLocationCode())
                .ne(entity.getId() != null, RfidLocation::getId, entity.getId()));
             if (exists) {
                 throw new ServiceException("位置编号已存在");
             }
        }
    }

    /**
     * 校验并批量删除位置信息信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            for (Long id : ids) {
                if (baseMapper.exists(new LambdaQueryWrapper<RfidLocation>().eq(RfidLocation::getParentId, id))) {
                    throw new ServiceException("存在子节点,无法删除");
                }
            }
        }
        return baseMapper.deleteByIds(ids) > 0;
    }
}
