package com.usky.sas.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.sas.domain.SasMapDevice;
import com.usky.sas.domain.SasMaps;
import com.usky.sas.domain.SasDevice;
import com.usky.sas.domain.SasPic;
import com.usky.sas.domain.SasPicSource;
import com.usky.sas.enums.SystemTypeCodeEnum;
import com.usky.sas.mapper.SasMapDeviceMapper;
import com.usky.sas.mapper.SasMapsMapper;
import com.usky.sas.mapper.SasPicMapper;
import com.usky.sas.mapper.SasDeviceMapper;
import com.usky.sas.common.util.GetIpUtils;
import com.usky.sas.service.SasMapService;
import com.usky.sas.service.SasMapDeviceService;
import com.usky.sas.service.SasPicService;
import com.usky.sas.service.SasPicSourceService;
import com.usky.sas.service.vo.MapDeviceBindRequest;
import com.usky.sas.service.vo.MapListItem;
import com.usky.sas.service.vo.MapPageRequest;
import com.usky.sas.service.vo.MapSaveRequest;
import com.usky.sas.service.vo.MapSaveWithDevicesRequest;
import com.usky.sas.service.vo.MapTreeItem;
import com.usky.sas.service.vo.MapInfoVo;
import com.usky.sas.service.vo.PicAddRequest;
import com.usky.sas.service.vo.PicSourceInfo;
import com.usky.sas.service.vo.PicSourcePageRequest;
import com.usky.sas.service.vo.PicSourceUpdateRequest;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SasMapServiceImpl extends AbstractCrudService<SasMapsMapper, SasMaps>
        implements SasMapService {

    @Autowired
    private SasMapDeviceMapper mapDeviceMapper;

    @Autowired
    private SasMapDeviceService mapDeviceService;

    @Autowired
    private SasPicMapper sasPicMapper;

    @Autowired
    private SasDeviceMapper sasDeviceMapper;

    @Autowired
    private SasPicService sasPicService;

    @Autowired
    private SasPicSourceService sasPicSourceService;

    @Value("${server.protocol:http}")
    private String protocol;

    @Value("${server.port:8080}")
    private String port;

    @Override
    public CommonPage<MapListItem> page(MapPageRequest request) {
        IPage<SasMaps> page = new Page<>(request.getCurrent(), request.getSize());
        LambdaQueryWrapper<SasMaps> wrapper = new LambdaQueryWrapper<>();
        // 电子地图配置不展示：视频导出防护(1003)、实时电子巡检(1008) 模块的地图
/*        wrapper.notIn(SasMaps::getType,
                SystemTypeCodeEnum.usbalarm.getCode(),
                SystemTypeCodeEnum.patrol.getCode());*/
        if (request.getParentId() != null && !request.getParentId().isEmpty()) {
            wrapper.eq(SasMaps::getParentId, request.getParentId());
        }
        if (request.getMapId() != null && !request.getMapId().isEmpty()) {
            wrapper.eq(SasMaps::getId, request.getMapId());
        }
        wrapper.orderByDesc(SasMaps::getCreateTime);
        page = this.page(page, wrapper);

        List<SasMaps> records = page.getRecords();
        if (records == null || records.isEmpty()) {
            return new CommonPage<>(Collections.emptyList(), page.getTotal(), page.getCurrent(), page.getSize());
        }

        List<String> mapIds = records.stream()
                .map(SasMaps::getId)
                .collect(Collectors.toList());

        LambdaQueryWrapper<SasMapDevice> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.in(SasMapDevice::getMapId, mapIds);
        List<SasMapDevice> mapDevices = mapDeviceMapper.selectList(deviceWrapper);
        Map<String, List<SasMapDevice>> deviceGroup = mapDevices.stream()
                .collect(Collectors.groupingBy(SasMapDevice::getMapId));

        List<MapListItem> items = records.stream().map(map -> {
            MapListItem item = new MapListItem();
            item.setId(map.getId());
            item.setName(map.getName());
            item.setType(map.getType());
            item.setRemark(map.getRemark());
            item.setParentId(map.getParentId());
            item.setWidth(map.getWidth());
            item.setHeight(map.getHeight());
            item.setIsMask(map.getIsMask());
            item.setBackImgId(map.getBackImgId());
            item.setCreateTime(map.getCreateTime());
            item.setUpdateTime(map.getUpdateTime());
            if (map.getBackImgId() != null && !map.getBackImgId().isEmpty()) {
                SasPic backPic = sasPicMapper.selectById(map.getBackImgId());
                if (backPic != null) {
                    String path = (backPic.getUrl() != null ? backPic.getUrl() : "") + (backPic.getPath() != null ? backPic.getPath() : "");
                    item.setBackImgUrl(path);
                }
            }

            List<SasMapDevice> devices = deviceGroup.getOrDefault(map.getId(), Collections.emptyList());
            List<MapListItem.MapDeviceItem> deviceItems = devices.stream().map(d -> {
                MapListItem.MapDeviceItem di = new MapListItem.MapDeviceItem();
                di.setId(d.getId());
                di.setDeviceId(d.getDeviceId());
                di.setMapId(d.getMapId());
                di.setImgId(d.getImgId());
                di.setDeviceName(d.getText());
                di.setType(d.getType());
                di.setX(d.getX() != null ? d.getX().doubleValue() : null);
                di.setY(d.getY() != null ? d.getY().doubleValue() : null);
                di.setWidth(d.getWidth());
                di.setHeight(d.getHeight());
                di.setAngle(d.getAngle());
                di.setBackgroundColor(d.getBackgroundColor());
                di.setFontColor(d.getFontColor());
                di.setThickness(d.getThickness());
                di.setFontSize(d.getFontSize());
                di.setText(d.getText());
                if (d.getImgId() != null && !d.getImgId().isEmpty()) {
                    SasPic imgPic = sasPicMapper.selectById(d.getImgId());
                    if (imgPic != null) {
                        String path = (imgPic.getUrl() != null ? imgPic.getUrl() : "") + (imgPic.getPath() != null ? imgPic.getPath() : "");
                        di.setImgUrl(path);
                    }
                }
                SasDevice device = sasDeviceMapper.selectById(d.getDeviceId());
                if (device != null) {
                    MapListItem.DeviceInfoVo deviceInfo = new MapListItem.DeviceInfoVo();
                    deviceInfo.setId(device.getId());
                    deviceInfo.setDeviceId(device.getDeviceId());
                    deviceInfo.setChannel(device.getChannel());
                    deviceInfo.setIpAddr(device.getIpAddr());
                    deviceInfo.setPort(device.getPort());
                    deviceInfo.setAddress(device.getAddress());
                    deviceInfo.setNote(device.getNote());
                    SystemTypeCodeEnum typeEnum = SystemTypeCodeEnum.getByCode(device.getDeviceType());
                    deviceInfo.setDeviceType(typeEnum != null ? typeEnum.getMessage() : null);
                    di.setDeviceInfo(deviceInfo);
                }
                return di;
            }).collect(Collectors.toList());
            item.setDevices(deviceItems);
            return item;
        }).collect(Collectors.toList());

        return new CommonPage<>(items, page.getTotal(), page.getCurrent(), page.getSize());
    }

    @Override
    public String create(MapSaveRequest request) {
        SasMaps map = new SasMaps();
        String id = UUID.randomUUID().toString();
        map.setId(id);
        applyMap(map, request);
        LocalDateTime now = LocalDateTime.now();
        map.setCreateTime(now);
        map.setUpdateTime(now);
        this.save(map);
        return id;
    }

    @Override
    public void update(String id, MapSaveRequest request) {
        SasMaps map = this.getById(id);
        if (map == null) {
            return;
        }
        applyMap(map, request);
        map.setUpdateTime(LocalDateTime.now());
        this.updateById(map);
    }

    @Override
    public void delete(String id) {
        deleteRecursively(id);
    }

    @Override
    public String bindDevice(String mapId, MapDeviceBindRequest request) {
        SasMapDevice mapDevice = new SasMapDevice();
        String id = UUID.randomUUID().toString();
        mapDevice.setId(id);
        mapDevice.setMapId(mapId);
        mapDevice.setDeviceId(request.getDeviceId());
        mapDevice.setImgId(request.getImgId());
        mapDevice.setType(request.getType());
        if (request.getX() != null) {
            mapDevice.setX(BigDecimal.valueOf(request.getX()));
        }
        if (request.getY() != null) {
            mapDevice.setY(BigDecimal.valueOf(request.getY()));
        }
        mapDevice.setWidth(request.getWidth());
        mapDevice.setHeight(request.getHeight());
        mapDevice.setAngle(request.getAngle());
        mapDevice.setText(request.getText());
        LocalDateTime now = LocalDateTime.now();
        mapDevice.setCreateTime(now);
        mapDevice.setUpdateTime(now);
        mapDeviceMapper.insert(mapDevice);
        return id;
    }

    @Override
    public void unbindDevice(String mapId, String deviceId) {
        LambdaQueryWrapper<SasMapDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SasMapDevice::getMapId, mapId)
                .eq(SasMapDevice::getDeviceId, deviceId);
        mapDeviceMapper.delete(wrapper);
    }

    @Override
    public void saveMapInfo(MapSaveWithDevicesRequest request) {
        log.info("请求参数：request={}", request);
        // 1. 保存或更新地图基础信息
        SasMaps map = null;
        if (StrUtil.isNotBlank(request.getId())) {
            map = this.getById(request.getId());
        }
        LocalDateTime now = LocalDateTime.now();
        if (map == null) {
            map = new SasMaps();
            String id = StrUtil.isNotBlank(request.getId()) ? request.getId() : IdUtil.fastSimpleUUID();
            map.setId(id);
            map.setCreateTime(now);
        }
        MapSaveRequest saveReq = new MapSaveRequest();
        saveReq.setName(request.getName());
        saveReq.setType(request.getType());
        saveReq.setRemark(request.getRemark());
        saveReq.setParentId(request.getParentId());
        saveReq.setWidth(request.getWidth());
        saveReq.setHeight(request.getHeight());
        saveReq.setIsMask(request.getIsMask());
        saveReq.setBackImgId(request.getBackImgId());
        applyMap(map, saveReq);
        map.setUpdateTime(now);
        this.saveOrUpdate(map);

        String mapId = map.getId();
        List<MapSaveWithDevicesRequest.MapDeviceItem> deviceItems = request.getDevices();

        // 2. 查询该地图下已有设备点位，删除“数据库有而本次请求没有”的
        LambdaQueryWrapper<SasMapDevice> query = new LambdaQueryWrapper<>();
        query.eq(SasMapDevice::getMapId, mapId);
        List<SasMapDevice> dbList = mapDeviceService.list(query);
        if (CollUtil.isNotEmpty(dbList)) {
            Set<String> dbIds = dbList.stream().map(SasMapDevice::getId).collect(Collectors.toSet());
            Set<String> newIds = deviceItems == null ? Collections.emptySet()
                    : deviceItems.stream()
                            .map(MapSaveWithDevicesRequest.MapDeviceItem::getId)
                            .filter(StrUtil::isNotBlank)
                            .collect(Collectors.toSet());
            dbIds.removeAll(newIds);
            if (CollUtil.isNotEmpty(dbIds)) {
                mapDeviceService.removeByIds(dbIds);
            }
        }

        // 3. 新增或更新设备点位：id 为空则生成 UUID，统一设置 mapId 后批量保存
        if (CollUtil.isNotEmpty(deviceItems)) {
            List<SasMapDevice> entities = deviceItems.stream()
                    .map(item -> toMapDeviceEntity(item, mapId, now))
                    .collect(Collectors.toList());
            entities.forEach(entity -> {
                if (StrUtil.isBlank(entity.getId())) {
                    entity.setId(IdUtil.fastSimpleUUID());
                }
                entity.setMapId(mapId);
                entity.setUpdateTime(now);
            });
            mapDeviceService.saveOrUpdateBatch(entities);
        }
    }

    /** 将请求中的设备点位项转为实体（id 可为空，由 saveMapInfo 统一补全） */
    private SasMapDevice toMapDeviceEntity(MapSaveWithDevicesRequest.MapDeviceItem item, String mapId, LocalDateTime now) {
        SasMapDevice entity = new SasMapDevice();
        if (StrUtil.isNotBlank(item.getId())) {
            entity.setId(item.getId());
        }
        entity.setMapId(mapId);
        entity.setDeviceId(item.getDeviceId());
        entity.setImgId(item.getImgId());
        entity.setType(item.getType());
        entity.setBackgroundColor(item.getBackgroundColor());
        entity.setX(item.getX() != null ? BigDecimal.valueOf(item.getX()) : null);
        entity.setY(item.getY() != null ? BigDecimal.valueOf(item.getY()) : null);
        entity.setWidth(item.getWidth());
        entity.setHeight(item.getHeight());
        entity.setAngle(item.getAngle());
        entity.setFontColor(item.getFontColor());
        entity.setThickness(item.getThickness());
        entity.setFontSize(item.getFontSize());
        entity.setText(item.getText());
        entity.setCreateTime(now);
        entity.setUpdateTime(now);
        return entity;
    }

    @Override
    public List<MapTreeItem> getMapTree() {
        // 电子地图配置不展示：视频导出防护(1003)、实时电子巡检(1008) 模块的地图
        LambdaQueryWrapper<SasMaps> wrapper = new LambdaQueryWrapper<>();
        wrapper.notIn(SasMaps::getType,
                SystemTypeCodeEnum.usbalarm.getCode(),
                SystemTypeCodeEnum.patrol.getCode());
        List<SasMaps> maps = this.list(wrapper);
        if (maps == null || maps.isEmpty()) {
            return Collections.emptyList();
        }

        // 先将所有节点转换为 MapTreeItem，并放入 map 方便后续组装 children
        Map<String, MapTreeItem> nodeMap = new HashMap<>();
        for (SasMaps m : maps) {
            MapTreeItem node = new MapTreeItem();
            node.setId(m.getId());
            node.setName(m.getName());
            node.setType(m.getType());
            node.setRemark(m.getRemark());
            node.setParentId(m.getParentId());
            node.setWidth(m.getWidth());
            node.setHeight(m.getHeight());
            node.setIsMask(m.getIsMask());
            node.setBackImgId(m.getBackImgId());
            node.setCreateTime(m.getCreateTime());
            node.setUpdateTime(m.getUpdateTime());
            nodeMap.put(m.getId(), node);
        }

        // 组装树结构
        List<MapTreeItem> roots = new java.util.ArrayList<>();
        for (SasMaps m : maps) {
            MapTreeItem node = nodeMap.get(m.getId());
            if (m.getParentId() == null || m.getParentId().isEmpty()) {
                roots.add(node);
            } else {
                MapTreeItem parent = nodeMap.get(m.getParentId());
                if (parent != null) {
                    parent.getChildren().add(node);
                } else {
                    // 若找不到父节点，则作为根节点返回，避免数据丢失
                    roots.add(node);
                }
            }
        }
        return roots;
    }

    @Override
    public List<MapTreeItem> getMapTreeByType(Integer type) {
        if (type == null) {
            return Collections.emptyList();
        }
        LambdaQueryWrapper<SasMaps> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SasMaps::getType, type);
        List<SasMaps> maps = this.list(wrapper);
        if (maps == null || maps.isEmpty()) {
            return Collections.emptyList();
        }
        Map<String, MapTreeItem> nodeMap = new HashMap<>();
        for (SasMaps m : maps) {
            MapTreeItem node = new MapTreeItem();
            node.setId(m.getId());
            node.setName(m.getName());
            node.setType(m.getType());
            node.setRemark(m.getRemark());
            node.setParentId(m.getParentId());
            node.setWidth(m.getWidth());
            node.setHeight(m.getHeight());
            node.setIsMask(m.getIsMask());
            node.setBackImgId(m.getBackImgId());
            node.setCreateTime(m.getCreateTime());
            node.setUpdateTime(m.getUpdateTime());
            nodeMap.put(m.getId(), node);
        }
        List<MapTreeItem> roots = new java.util.ArrayList<>();
        for (SasMaps m : maps) {
            MapTreeItem node = nodeMap.get(m.getId());
            if (m.getParentId() == null || m.getParentId().isEmpty()) {
                roots.add(node);
            } else {
                MapTreeItem parent = nodeMap.get(m.getParentId());
                if (parent != null) {
                    parent.getChildren().add(node);
                } else {
                    roots.add(node);
                }
            }
        }
        return roots;
    }

    @Override
    public MapInfoVo getMapInfo(String mapId) {
        SasMaps maps = getById(mapId);
        if (maps == null) {
            return null;
        }
        MapInfoVo vo = new MapInfoVo();
        BeanUtils.copyProperties(maps, vo);
        if (maps.getBackImgId() != null && !maps.getBackImgId().isEmpty()) {
            SasPic pic = sasPicMapper.selectById(maps.getBackImgId());
            if (pic != null) {
                String baseUrl = protocol + "://" + GetIpUtils.getServerIP() + ":" + port;
                String path = (pic.getUrl() != null ? pic.getUrl() : "") + (pic.getPath() != null ? pic.getPath() : "");
                vo.setBackImgUrl(baseUrl + path);
            }
        }
        LambdaQueryWrapper<SasMapDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SasMapDevice::getMapId, mapId);
        List<SasMapDevice> list = mapDeviceMapper.selectList(wrapper);
        List<MapInfoVo.MapDeviceInfoVo> collect = list.stream().map(mapDevice -> {
            MapInfoVo.MapDeviceInfoVo dvo = new MapInfoVo.MapDeviceInfoVo();
            dvo.setId(mapDevice.getId());
            dvo.setDeviceId(mapDevice.getDeviceId());
            dvo.setMapId(mapDevice.getMapId());
            dvo.setImgId(mapDevice.getImgId());
            dvo.setType(mapDevice.getType());
            dvo.setX(mapDevice.getX());
            dvo.setY(mapDevice.getY());
            dvo.setWidth(mapDevice.getWidth());
            dvo.setHeight(mapDevice.getHeight());
            dvo.setAngle(mapDevice.getAngle());
            dvo.setText(mapDevice.getText());
            dvo.setCreateTime(mapDevice.getCreateTime());
            dvo.setUpdateTime(mapDevice.getUpdateTime());
            SasDevice device = sasDeviceMapper.selectById(mapDevice.getDeviceId());
            if (device != null) {
                MapInfoVo.DeviceInfoVo deviceInfo = new MapInfoVo.DeviceInfoVo();
                deviceInfo.setId(device.getId());
                deviceInfo.setDeviceId(device.getDeviceId());
                deviceInfo.setChannel(device.getChannel());
                deviceInfo.setIpAddr(device.getIpAddr());
                deviceInfo.setPort(device.getPort());
                deviceInfo.setAddress(device.getAddress());
                deviceInfo.setNote(device.getNote());
                SystemTypeCodeEnum typeEnum = SystemTypeCodeEnum.getByCode(device.getDeviceType());
                deviceInfo.setDeviceType(typeEnum != null ? typeEnum.getMessage() : null);
                dvo.setDeviceInfo(deviceInfo);
            }
            if (mapDevice.getImgId() != null && !mapDevice.getImgId().isEmpty()) {
                SasPic imgPic = sasPicMapper.selectById(mapDevice.getImgId());
                if (imgPic != null) {
                    String baseUrl = protocol + "://" + GetIpUtils.getServerIP() + ":" + port;
                    String path = (imgPic.getUrl() != null ? imgPic.getUrl() : "") + (imgPic.getPath() != null ? imgPic.getPath() : "");
                    dvo.setImgUrl(baseUrl + path);
                }
            }
            return dvo;
        }).collect(Collectors.toList());
        vo.setDeviceList(collect);
        return vo;
    }

    @Override
    public String addPic(PicAddRequest request) {
        if (request == null || request.getUrl() == null || request.getUrl().isEmpty()) {
            throw new BusinessException("图片地址 url 为必填");
        }
        SasPic pic = new SasPic();
        pic.setId(UUID.randomUUID().toString());
        pic.setUrl(request.getUrl());
        pic.setPath(request.getPath());
        LocalDateTime now = LocalDateTime.now();
        pic.setCreateTime(now);
        pic.setUpdateTime(now);
        sasPicService.save(pic);

        SasPicSource picSource = new SasPicSource();
        picSource.setId(UUID.randomUUID().toString());
        picSource.setPicId(pic.getId());
        picSource.setName(request.getName());
        picSource.setRemark(request.getRemark());
        picSource.setPicType(request.getPicType());
        picSource.setSubtype(request.getSubtype());
        picSource.setTag(request.getTag());
        picSource.setCreateTime(now);
        picSource.setUpdateTime(now);
        sasPicSourceService.save(picSource);

        return pic.getId();
    }

    @Override
    public CommonPage<PicSourceInfo> getPicSource(PicSourcePageRequest request) {
        if (request == null) {
            request = new PicSourcePageRequest();
        }
        Page<SasPicSource> page = new Page<>(
                request.getCurrent() != null ? request.getCurrent() : 1L,
                request.getSize() != null ? request.getSize() : 10L);
        LambdaQueryWrapper<SasPicSource> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(request.getPicType() != null, SasPicSource::getPicType, request.getPicType());
        com.baomidou.mybatisplus.core.metadata.IPage<SasPicSource> sourcePage = sasPicSourceService.page(page, wrapper);
        List<PicSourceInfo> list = sourcePage.getRecords().stream().map(picSource -> {
            PicSourceInfo info = new PicSourceInfo();
            BeanUtils.copyProperties(picSource, info);
            if (picSource.getPicId() != null && !picSource.getPicId().isEmpty()) {
                SasPic pic = sasPicService.getById(picSource.getPicId());
                if (pic != null) {
                    String path = (pic.getUrl() != null ? pic.getUrl() : "") + (pic.getPath() != null ? pic.getPath() : "");
                    info.setPicUrl(path);
                }
            }
            return info;
        }).collect(Collectors.toList());
        return new CommonPage<>(list, sourcePage.getTotal(), sourcePage.getCurrent(), sourcePage.getSize());
    }

    @Override
    public void updatePicSource(String id, PicSourceUpdateRequest request) {
        if (id == null || id.isEmpty()) {
            throw new BusinessException("图片资源 id 不能为空");
        }
        SasPicSource picSource = sasPicSourceService.getById(id);
        if (picSource == null) {
            throw new BusinessException("图片资源不存在");
        }
        if (request != null) {
            if (request.getName() != null) {
                picSource.setName(request.getName());
            }
            if (request.getRemark() != null) {
                picSource.setRemark(request.getRemark());
            }
            if (request.getPicType() != null) {
                picSource.setPicType(request.getPicType());
            }
            if (request.getSubtype() != null) {
                picSource.setSubtype(request.getSubtype());
            }
            if (request.getTag() != null) {
                picSource.setTag(request.getTag());
            }
            LocalDateTime now = LocalDateTime.now();
            picSource.setUpdateTime(now);
            sasPicSourceService.updateById(picSource);

            if ((request.getUrl() != null || request.getPath() != null) && picSource.getPicId() != null && !picSource.getPicId().isEmpty()) {
                SasPic pic = sasPicService.getById(picSource.getPicId());
                if (pic != null) {
                    if (request.getUrl() != null) {
                        pic.setUrl(request.getUrl());
                    }
                    if (request.getPath() != null) {
                        pic.setPath(request.getPath());
                    }
                    pic.setUpdateTime(now);
                    sasPicService.updateById(pic);
                }
            }
        }
    }

    @Override
    public void deletePicSource(String id) {
        if (id == null || id.isEmpty()) {
            throw new BusinessException("图片资源 id 不能为空");
        }
        sasPicSourceService.removeById(id);
    }

    /**
     * 递归删除地图及其子地图，同时删除绑定设备
     */
    private void deleteRecursively(String id) {
        // 删除子地图
        LambdaQueryWrapper<SasMaps> childWrapper = new LambdaQueryWrapper<>();
        childWrapper.eq(SasMaps::getParentId, id);
        List<SasMaps> children = this.list(childWrapper);
        if (children != null && !children.isEmpty()) {
            for (SasMaps child : children) {
                deleteRecursively(child.getId());
            }
        }

        // 删除当前地图下绑定设备
        LambdaQueryWrapper<SasMapDevice> deviceWrapper = new LambdaQueryWrapper<>();
        deviceWrapper.eq(SasMapDevice::getMapId, id);
        mapDeviceMapper.delete(deviceWrapper);

        // 删除当前地图
        this.removeById(id);
    }

    private void applyMap(SasMaps map, MapSaveRequest request) {
        map.setName(request.getName());
        map.setType(request.getType());
        map.setRemark(request.getRemark());
        map.setParentId(request.getParentId());
        map.setWidth(request.getWidth());
        map.setHeight(request.getHeight());
        map.setIsMask(request.getIsMask());
        map.setBackImgId(request.getBackImgId());
    }
}

