package com.usky.eg.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.core.util.UUIDUtils;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.eg.domain.EgDevice;
import com.usky.eg.domain.EgDeviceHeartbeat;
import com.usky.eg.domain.EgDevicePersonBind;
import com.usky.eg.domain.EgRecord;
import com.usky.eg.domain.SysPerson;
import com.usky.eg.mapper.EgDeviceMapper;
import com.usky.eg.mapper.EgDeviceHeartbeatMapper;
import com.usky.eg.mapper.EgDevicePersonBindMapper;
import com.usky.eg.mapper.EgRecordMapper;
import com.usky.eg.mapper.SysPersonMapper;
import com.usky.eg.service.EgDeviceService;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.eg.service.vo.EgDeviceBindFacePersonQueryVO;
import com.usky.eg.service.vo.EgDeviceBindFacePersonVO;
import com.usky.eg.service.vo.EgDeviceRequestVO;
import com.usky.iot.RemoteIotTaskService;
import com.usky.transfer.RemoteTransferService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * <p>
 * 门禁_设备信息表 服务实现类
 * </p>
 *
 * @author zyj
 * @since 2024-11-27
 */
@Service
public class EgDeviceServiceImpl extends AbstractCrudService<EgDeviceMapper, EgDevice> implements EgDeviceService {
    @Autowired
    private EgDeviceMapper egDeviceMapper;
    @Autowired
    private EgDeviceHeartbeatMapper egDeviceHeartbeatMapper;
    @Autowired
    private RemoteIotTaskService remoteIotTaskService;
    @Autowired
    private RemoteTransferService remoteTransferService;
    @Autowired
    private EgDevicePersonBindMapper egDevicePersonBindMapper;
    @Autowired
    private EgRecordMapper egRecordMapper;
    @Autowired
    private SysPersonMapper sysPersonMapper;

    @Override
    public CommonPage<EgDevice> page(EgDeviceRequestVO requestVO){
        IPage<EgDevice> page = new Page<>(requestVO.getCurrent(),requestVO.getSize());
        Integer tenantId;

        if(StringUtils.isNotBlank(requestVO.getDeviceCode())){
            LambdaQueryWrapper<EgDevice> tempQueryWrapper = new LambdaQueryWrapper<>();
            tempQueryWrapper.eq(EgDevice::getDeviceCode, requestVO.getDeviceCode());
            EgDevice tempDevice = egDeviceMapper.selectOne(tempQueryWrapper);
            if(tempDevice == null){
                // 未查询到数据，返回空数组
                return new CommonPage<>(new ArrayList<>(), 0L, requestVO.getSize(), requestVO.getCurrent());
            }
            tenantId = tempDevice.getTenantId();
        }else{
            tenantId = SecurityUtils.getTenantId();
        }

        LambdaQueryWrapper<EgDevice> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StringUtils.isNotBlank(requestVO.getDeviceName()),EgDevice::getDeviceName,requestVO.getDeviceName())
                .like(StringUtils.isNotBlank(requestVO.getInstallAddress()),EgDevice::getInstallAddress,requestVO.getInstallAddress())
                .eq(null != requestVO.getServiceStatus(),EgDevice::getServiceStatus,requestVO.getServiceStatus())
                .eq(null != requestVO.getId(),EgDevice::getId,requestVO.getId())
                .eq(null != requestVO.getDeviceUuid(),EgDevice::getDeviceUuid, requestVO.getDeviceUuid())
                .eq(StringUtils.isNotBlank(requestVO.getDeviceCode()),EgDevice::getDeviceCode, requestVO.getDeviceCode())
                .eq(EgDevice::getTenantId,tenantId)
                .orderByDesc(EgDevice::getId);
        page = this.page(page,queryWrapper);

        if(!page.getRecords().isEmpty()){
            // 检查设备心跳
            List<String> validDeviceCodes = new ArrayList<>();
            Map<String, EgDevice> deviceCodeMap = new HashMap<>();
            for (EgDevice device : page.getRecords()) {
                String deviceCode = device.getDeviceCode();
                if (StringUtils.isNotBlank(deviceCode)) {
                    validDeviceCodes.add(deviceCode);
                    deviceCodeMap.put(deviceCode, device);
                } else {
                    // deviceCode为空，直接设置为离线
                    device.setDeviceStatus(0);
                }
            }

            // 批量查询心跳数据
            if (!validDeviceCodes.isEmpty()) {
                LambdaQueryWrapper<EgDeviceHeartbeat> heartbeatQueryWrapper = Wrappers.lambdaQuery();
                heartbeatQueryWrapper.in(EgDeviceHeartbeat::getDeviceCode, validDeviceCodes)
                        .orderByDesc(EgDeviceHeartbeat::getCreateTime);
                List<EgDeviceHeartbeat> heartbeatList = egDeviceHeartbeatMapper.selectList(heartbeatQueryWrapper);
                
                // 构建deviceCode到最新心跳记录的映射，并同时设置deviceStatus
                Map<String, EgDeviceHeartbeat> deviceHeartbeatMap = new HashMap<>();
                for (EgDeviceHeartbeat heartbeat : heartbeatList) {
                    String deviceCode = heartbeat.getDeviceCode();
                    if (StringUtils.isNotBlank(deviceCode)) {
                        // 如果已存在，保留最新的（因为已按createTime降序排列）
                        if (deviceHeartbeatMap.putIfAbsent(deviceCode, heartbeat) == null) {
                            // 首次遇到该deviceCode，从心跳表直接获取deviceStatus并设置到EgDevice
                            EgDevice device = deviceCodeMap.get(deviceCode);
                            if (device != null && heartbeat.getDeviceStatus() != null) {
                                device.setDeviceStatus(heartbeat.getDeviceStatus());
                            }
                        }
                    }
                }
                
                // 如果未找到对应的设备心跳记录，则设置DeviceStatus为0（离线）
                for (String deviceCode : validDeviceCodes) {
                    if (!deviceHeartbeatMap.containsKey(deviceCode)) {
                        EgDevice device = deviceCodeMap.get(deviceCode);
                        if (device != null) {
                            device.setDeviceStatus(0);
                        }
                    }
                }
            } else {
                // 如果没有有效的deviceCode，将所有设备的deviceStatus设置为0
                for (EgDevice device : page.getRecords()) {
                    device.setDeviceStatus(0);
                }
            }

        }

        // 查询并填充绑定人员信息（来自 eg_device_person_bind，person_id 逗号分隔后写入 bindPerson 字段）
        if (!page.getRecords().isEmpty()) {
            fillBindPerson(page.getRecords());
        }

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

    @Override
    public CommonPage<EgDevice> wePage(EgDeviceRequestVO requestVO){
        long userId = SecurityUtils.getUserId();
        // 通过 sys_user_person -> sys_person -> eg_device_person_bind -> eg_device 查询当前用户绑定的设备ID列表
        List<Integer> deviceIds = egDevicePersonBindMapper.selectDeviceIdsByUserId(userId);
        if (CollectionUtils.isEmpty(deviceIds)) {
            // 未绑定任何设备，返回空分页
            return new CommonPage<>(new ArrayList<>(), 0L, requestVO.getSize(), requestVO.getCurrent());
        }

        IPage<EgDevice> page = new Page<>(requestVO.getCurrent(),requestVO.getSize());
        LambdaQueryWrapper<EgDevice> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.like(StringUtils.isNotBlank(requestVO.getDeviceName()),EgDevice::getDeviceName,requestVO.getDeviceName())
                .like(StringUtils.isNotBlank(requestVO.getInstallAddress()),EgDevice::getInstallAddress,requestVO.getInstallAddress())
                .eq(null != requestVO.getServiceStatus(),EgDevice::getServiceStatus,requestVO.getServiceStatus())
                .eq(null != requestVO.getId(),EgDevice::getId,requestVO.getId())
                .in(EgDevice::getId, deviceIds)
                .eq(EgDevice::getTenantId,SecurityUtils.getTenantId())
                .orderByDesc(EgDevice::getId);
        page = this.page(page,queryWrapper);

        // 查询并填充绑定人员信息
        if (!page.getRecords().isEmpty()) {
            fillBindPerson(page.getRecords());
        }

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

    @Override
    public void add(EgDevice egDevice) {
        LocalDateTime now = LocalDateTime.now();
        
        // 1. 校验设备名称唯一性
        if (checkDeviceNameUnique(egDevice)) {
            throw new BusinessException("新增门禁设备'" + egDevice.getDeviceName() + "'失败，设备已存在");
        }

        // 2. 校验设备IP是否已被绑定
        if (StringUtils.isNotBlank(egDevice.getDeviceIp())) {
            LambdaQueryWrapper<EgDevice> ipCheckWrapper = Wrappers.lambdaQuery();
            ipCheckWrapper.eq(EgDevice::getDeviceIp, egDevice.getDeviceIp())
                    .eq(EgDevice::getTenantId, SecurityUtils.getTenantId());
            EgDevice existingDeviceByIp = this.getOne(ipCheckWrapper);
            if (existingDeviceByIp != null) {
                throw new BusinessException("设备IP'" + egDevice.getDeviceIp() + "'已被设备'" 
                        + existingDeviceByIp.getDeviceName() + "'绑定，请更换IP或检查设备配置！");
            }
        }

        // 3. 若未传deviceCode但传了deviceIp，尝试从心跳表中获取deviceCode
        if (StringUtils.isBlank(egDevice.getDeviceCode()) && StringUtils.isNotBlank(egDevice.getDeviceIp())) {
            LambdaQueryWrapper<EgDeviceHeartbeat> heartbeatCheckWrapper = Wrappers.lambdaQuery();
            heartbeatCheckWrapper.eq(EgDeviceHeartbeat::getIpAddr, egDevice.getDeviceIp())
                    .eq(EgDeviceHeartbeat::getDeviceStatus, 1);
            EgDeviceHeartbeat heartbeat = egDeviceHeartbeatMapper.selectOne(heartbeatCheckWrapper);
            if (heartbeat != null && StringUtils.isNotBlank(heartbeat.getDeviceCode())) {
                egDevice.setDeviceCode(heartbeat.getDeviceCode());
            }
        }

        // 4. 校验设备编码是否已被绑定
        if (StringUtils.isNotBlank(egDevice.getDeviceCode())) {
            LambdaQueryWrapper<EgDevice> codeCheckWrapper = Wrappers.lambdaQuery();
            codeCheckWrapper.eq(EgDevice::getDeviceCode, egDevice.getDeviceCode())
                    .eq(EgDevice::getTenantId, SecurityUtils.getTenantId());
            EgDevice existingDeviceByCode = this.getOne(codeCheckWrapper);
            if (existingDeviceByCode != null) {
                throw new BusinessException("设备编码'" + egDevice.getDeviceCode() + "'已被设备'" 
                        + existingDeviceByCode.getDeviceName() + "'绑定，请更换设备编码或检查设备配置！");
            }
        }

        // 5. 设置设备基本信息
        egDevice.setDeviceUuid(UUIDUtils.uuid());
        egDevice.setCreateBy(SecurityUtils.getUsername());
        egDevice.setCreateTime(now);
        egDevice.setTenantId(SecurityUtils.getTenantId());
        egDevice.setOpenMode("人脸");
        egDevice.setWorkStatus("4");

        // 6. 保存设备
        this.save(egDevice);

        // 7. 异步调用远程服务添加设备信息，静默处理异常，不影响设备保存成功
        String deviceUuid = egDevice.getDeviceUuid();
        String deviceName = egDevice.getDeviceName();
        if (StringUtils.isNotBlank(deviceUuid) && StringUtils.isNotBlank(deviceName)) {
            String installAddress = StringUtils.isNotBlank(egDevice.getInstallAddress()) 
                    ? egDevice.getInstallAddress() 
                    : "";
            Integer serviceStatus = egDevice.getServiceStatus() != null 
                    ? egDevice.getServiceStatus() 
                    : 1;
            
            CompletableFuture.runAsync(() -> {
                try {
                    remoteIotTaskService.addDeviceInfo("502_USKY", deviceUuid, deviceUuid, 
                            deviceName, installAddress, serviceStatus);
                } catch (Exception e) {
                    // 远程服务调用失败，静默处理，不影响设备保存成功
                }
            });
        }
    }

    @Override
    public void update(EgDevice egDevice) {
        if(checkDeviceNameUnique(egDevice)){
            throw new BusinessException("修改门禁设备'"+egDevice.getDeviceName()+"'失败，设备名称已存在");
        }

        // 校验设备IP是否已被其他设备绑定（排除当前设备）
        if (StringUtils.isNotBlank(egDevice.getDeviceIp())) {
            LambdaQueryWrapper<EgDevice> ipCheckWrapper = Wrappers.lambdaQuery();
            ipCheckWrapper.eq(EgDevice::getDeviceIp, egDevice.getDeviceIp())
                    .eq(EgDevice::getTenantId, SecurityUtils.getTenantId())
                    .ne(EgDevice::getId, egDevice.getId());
            EgDevice existingDeviceByIp = this.getOne(ipCheckWrapper);
            if (existingDeviceByIp != null) {
                throw new BusinessException("设备IP'" + egDevice.getDeviceIp() + "'已被设备'" 
                        + existingDeviceByIp.getDeviceName() + "'绑定，请更换IP或检查设备配置！");
            }
        }

        // 若传了deviceIp，尝试从心跳表中获取deviceCode
        if (StringUtils.isNotBlank(egDevice.getDeviceIp())) {
            LambdaQueryWrapper<EgDeviceHeartbeat> heartbeatCheckWrapper = Wrappers.lambdaQuery();
            heartbeatCheckWrapper.eq(EgDeviceHeartbeat::getIpAddr, egDevice.getDeviceIp())
                    .eq(EgDeviceHeartbeat::getDeviceStatus, 1);
            EgDeviceHeartbeat heartbeat = egDeviceHeartbeatMapper.selectOne(heartbeatCheckWrapper);
            if (heartbeat != null && StringUtils.isNotBlank(heartbeat.getDeviceCode())) {
                egDevice.setDeviceCode(heartbeat.getDeviceCode());
            }
        }

        // 校验设备编码是否已被其他设备绑定（排除当前设备）
        if (StringUtils.isNotBlank(egDevice.getDeviceCode())) {
            LambdaQueryWrapper<EgDevice> codeCheckWrapper = Wrappers.lambdaQuery();
            codeCheckWrapper.eq(EgDevice::getDeviceCode, egDevice.getDeviceCode())
                    .eq(EgDevice::getTenantId, SecurityUtils.getTenantId())
                    .ne(EgDevice::getId, egDevice.getId());
            EgDevice existingDeviceByCode = this.getOne(codeCheckWrapper);
            if (existingDeviceByCode != null) {
                throw new BusinessException("设备编码'" + egDevice.getDeviceCode() + "'已被设备'" 
                        + existingDeviceByCode.getDeviceName() + "'绑定，请更换设备编码或检查设备配置！");
            }
        }

        egDevice.setUpdateBy(SecurityUtils.getUsername());
        egDevice.setUpdateTime(LocalDateTime.now());

        this.updateById(egDevice);
    }

    @Override
    public void attachUpdate(EgDevice egDevice){
        if(checkDeviceNameUnique(egDevice)){
            throw new BusinessException("新增门禁设备'"+egDevice.getDeviceName()+"'失败，设备已存在");
        }

        egDevice.setUpdateBy(SecurityUtils.getUsername());
        egDevice.setUpdateTime(LocalDateTime.now());

        this.updateById(egDevice);
    }

    @Override
    public void remove(Integer id){
        EgDevice egDevice = this.getById(id);
        Optional.ofNullable(egDevice).orElseThrow(() -> new BusinessException("门禁设备信息不存在"));

        // 校验 eg_device_person_bind 是否存在绑定人员
        Integer personBindCount = egDevicePersonBindMapper.countByDeviceId(id);
        if (personBindCount != null && personBindCount > 0) {
            throw new BusinessException("已绑定人员不能删除");
        }

        this.removeById(id);

        // 异步调用远程服务删除设备信息，静默处理异常，不影响设备删除
        String deviceUuid = egDevice.getDeviceUuid();
        if (StringUtils.isNotBlank(deviceUuid)) {
            CompletableFuture.runAsync(() -> {
                try {
                    remoteIotTaskService.deleteDeviceInfo(deviceUuid);
                } catch (Exception e) {
                    // 远程服务调用失败，静默处理，不影响设备删除
                }
            });
        }
    }

    /**
     * 根据设备ID集合查询 eg_device_person_bind，将 person_id 按逗号拼接后写入设备的 bindPerson 字段
     */
    private void fillBindPerson(List<EgDevice> devices) {
        if (CollectionUtils.isEmpty(devices)) {
            return;
        }

        List<Integer> deviceIds = new ArrayList<>();
        for (EgDevice device : devices) {
            if (device != null && device.getId() != null) {
                deviceIds.add(device.getId());
            }
        }

        if (deviceIds.isEmpty()) {
            return;
        }

        List<EgDevicePersonBind> bindList = egDevicePersonBindMapper.selectByDeviceIds(deviceIds);
        if (CollectionUtils.isEmpty(bindList)) {
            return;
        }

        Map<Integer, List<String>> devicePersonMap = new HashMap<>();
        for (EgDevicePersonBind bind : bindList) {
            if (bind.getDeviceId() == null || bind.getPersonId() == null) {
                continue;
            }
            devicePersonMap
                    .computeIfAbsent(bind.getDeviceId(), k -> new ArrayList<>())
                    .add(String.valueOf(bind.getPersonId()));
        }

        for (EgDevice device : devices) {
            if (device == null || device.getId() == null) {
                continue;
            }
            List<String> personIds = devicePersonMap.get(device.getId());
            if (personIds != null && !personIds.isEmpty()) {
                device.setBindPerson(String.join(",", personIds));
            } else {
                device.setBindPerson(null);
            }
        }
    }

    @Override
    public boolean checkNameUnique(EgDevice egDevice){
        Integer id = null == egDevice.getId() ? -1 : egDevice.getId();
        LambdaQueryWrapper<EgDevice> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(EgDevice::getDeviceId,egDevice.getDeviceId())
                .eq(EgDevice::getTenantId, SecurityUtils.getTenantId());
        EgDevice one = this.getOne(queryWrapper);
        return null != one && !Objects.equals(one.getId(),id);
    }

    @Override
    public boolean checkDeviceNameUnique(EgDevice egDevice){
        Integer id = null == egDevice.getId() ? -1 : egDevice.getId();
        LambdaQueryWrapper<EgDevice> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(EgDevice::getDeviceName,egDevice.getDeviceName())
                .eq(EgDevice::getTenantId, SecurityUtils.getTenantId());
        EgDevice one = this.getOne(queryWrapper);
        return null != one && !Objects.equals(one.getId(),id);
    }

    @Override
    public Map<String,Object> control(String productCode, String deviceUuid, String commandCode, String commandValue, Long userId, String userName, Integer categoryType, String gatewayUuid, Boolean skipCheck, Integer passType){
        // 1. 查询设备
        EgDevice device = this.getOne(Wrappers.<EgDevice>lambdaQuery()
                .select(EgDevice::getId, EgDevice::getTenantId)
                .eq(EgDevice::getDeviceUuid, deviceUuid));
        if (device == null) {
            throw new BusinessException("设备未注册，请先注册");
        }

        Integer tenantId = device.getTenantId();
        long commandUserId = userId != null ? userId : SecurityUtils.getUserId();
        String commandUserName = userName != null ? userName : SecurityUtils.getUsername();

        // 2. 权限校验
        if (!Boolean.TRUE.equals(skipCheck)) {
            Integer bindCount = egDevicePersonBindMapper.countByUserIdAndDeviceId(commandUserId, device.getId());
            if (bindCount == null || bindCount == 0) {
                saveRecord(device.getId(), tenantId, commandUserName, passType, "失败：暂无权限");
                throw new BusinessException("暂无权限");
            }
        }

        // 3. 构建下发命令参数
        Map<String,Object> params = new HashMap<>();
        params.put("commandCode", commandCode);
        params.put("commandValue", commandValue);
        Map<String,Object> map = new HashMap<>();
        map.put("method", "control");
        map.put("deviceUuid", deviceUuid);
        map.put("params", params);

        // 4. 下发命令并记录结果
        String targetUuid = categoryType == 3 ? gatewayUuid : deviceUuid;
        Map<String,Object> result = null;
        String passResult = "下发命令失败";
        try {
            result = remoteTransferService.deviceControl(productCode, targetUuid, JSON.toJSONString(map), tenantId, commandUserId, commandUserName);
            if (result == null || !Integer.valueOf(200).equals(result.get("code"))) {
                passResult = result != null && result.get("message") != null ? result.get("message").toString() : "下发命令失败";
                throw new BusinessException(passResult);
            }
            passResult = result.get("message") != null ? result.get("message").toString() : "下发命令成功";
            return result;
        } finally {
            saveRecord(device.getId(), tenantId, commandUserName, passType, passResult);
        }
    }

    /**
     * 插入通行记录，失败不影响主流程
     */
    private void saveRecord(Integer deviceId, Integer tenantId, String userName, Integer passType, String passResult) {
        try {
            EgRecord record = new EgRecord();
            record.setEgDeviceId(deviceId);
            record.setTenantId(tenantId);
            record.setPassTime(LocalDateTime.now());
            record.setCreateTime(LocalDateTime.now());
            record.setPassResult(passResult);
            record.setUserName(userName);
            record.setPassType(passType);
            egRecordMapper.insert(record);
        } catch (Exception ignored) {}
    }

    @Override
    public CommonPage<EgDeviceBindFacePersonVO> pageBindFacePersons(EgDeviceBindFacePersonQueryVO queryVO) {
        Integer cur = queryVO.getCurrent();
        Integer sz = queryVO.getSize();
        IPage<SysPerson> page = new Page<>(cur, sz);

        List<Integer> deviceIds = new ArrayList<>();
        if (StringUtils.isNotBlank(queryVO.getDeviceCode())) {
            EgDevice tempDevice = egDeviceMapper.selectOne(Wrappers.<EgDevice>lambdaQuery()
                    .eq(EgDevice::getDeviceCode, queryVO.getDeviceCode()));
            if (tempDevice == null) {
                return new CommonPage<>(new ArrayList<>(), 0L, sz, cur);
            }
            EgDevice device = egDeviceMapper.selectOne(Wrappers.<EgDevice>lambdaQuery()
                    .eq(EgDevice::getDeviceCode, queryVO.getDeviceCode())
                    .eq(EgDevice::getTenantId, tempDevice.getTenantId()));
            if (device == null || device.getId() == null) {
                return new CommonPage<>(new ArrayList<>(), 0L, sz, cur);
            }
            deviceIds.add(device.getId());
        } else {
            List<EgDevice> devices = egDeviceMapper.selectList(Wrappers.<EgDevice>lambdaQuery()
                    .eq(EgDevice::getTenantId, SecurityUtils.getTenantId()));
            if (!CollectionUtils.isEmpty(devices)) {
                for (EgDevice d : devices) {
                    if (d != null && d.getId() != null) {
                        deviceIds.add(d.getId());
                    }
                }
            }
        }

        if (deviceIds.isEmpty()) {
            return new CommonPage<>(new ArrayList<>(), 0L, sz, cur);
        }

        List<EgDevicePersonBind> bindList = egDevicePersonBindMapper.selectByDeviceIds(deviceIds);
        LinkedHashSet<Integer> personIdSet = new LinkedHashSet<>();
        if (!CollectionUtils.isEmpty(bindList)) {
            for (EgDevicePersonBind b : bindList) {
                if (b.getPersonId() != null) {
                    personIdSet.add(b.getPersonId());
                }
            }
        }
        if (personIdSet.isEmpty()) {
            return new CommonPage<>(new ArrayList<>(), 0L, sz, cur);
        }
        List<Integer> personIds = new ArrayList<>(personIdSet);

        LambdaQueryWrapper<SysPerson> personWrapper = Wrappers.lambdaQuery();
        personWrapper.in(SysPerson::getId, personIds);
        if (StringUtils.isNotBlank(queryVO.getFullName())) {
            personWrapper.like(SysPerson::getFullName, queryVO.getFullName());
        }
        Integer faceStatusFilter = queryVO.getFaceStatus();
        if (faceStatusFilter != null) {
            personWrapper.eq(SysPerson::getFaceStatus, faceStatusFilter.byteValue());
        }
        personWrapper.orderByAsc(SysPerson::getId);
        page = sysPersonMapper.selectPage(page, personWrapper);

        List<SysPerson> records = page.getRecords();
        List<Integer> pagePersonIds = new ArrayList<>();
        for (SysPerson p : records) {
            if (p != null && p.getId() != null) {
                pagePersonIds.add(p.getId());
            }
        }
        Map<Integer, Long> personUserIdMap = buildPersonUserIdMap(pagePersonIds);
        List<EgDeviceBindFacePersonVO> rows = new ArrayList<>(records.size());
        for (SysPerson p : records) {
            EgDeviceBindFacePersonVO vo = new EgDeviceBindFacePersonVO();
            vo.setId(p.getId());
            vo.setUserId(personUserIdMap.get(p.getId()));
            vo.setFullName(p.getFullName());
            vo.setAge(p.getAge());
            vo.setGender(p.getGender());
            vo.setLinkPhone(p.getLinkPhone());
            vo.setFaceBase(p.getFaceBase());
            vo.setVefNum(p.getVefNum());
            vo.setFaceStatus(p.getFaceStatus());
            vo.setCardNum(p.getCardNum());
            rows.add(vo);
        }
        return new CommonPage<>(rows, page.getTotal(), sz, cur);
    }

    private Map<Integer, Long> buildPersonUserIdMap(List<Integer> personIds) {
        Map<Integer, Long> map = new HashMap<>();
        if (CollectionUtils.isEmpty(personIds)) {
            return map;
        }
        List<Map<String, Object>> rows = sysPersonMapper.selectUserIdsByPersonIds(personIds);
        if (CollectionUtils.isEmpty(rows)) {
            return map;
        }
        for (Map<String, Object> row : rows) {
            if (row == null) {
                continue;
            }
            Object personIdObj = row.get("personId");
            Object userIdObj = row.get("userId");
            if (personIdObj == null || userIdObj == null) {
                continue;
            }
            map.put(Integer.valueOf(personIdObj.toString()), Long.valueOf(userIdObj.toString()));
        }
        return map;
    }

    @Override
    public void bindPerson(Integer deviceId, String personIds, Integer isLoginNotify) {
        if (deviceId == null) {
            throw new BusinessException("设备ID不能为空");
        }

        // 先校验设备是否存在
        EgDevice device = this.getById(deviceId);
        Optional.ofNullable(device).orElseThrow(() -> new BusinessException("门禁设备信息不存在"));

        // 先清空原有绑定关系
        egDevicePersonBindMapper.deleteByDeviceId(deviceId);

        // 为空则视为解绑所有人员
        if (!StringUtils.isNotBlank(personIds)) {
            return;
        }

        String[] personIdArr = personIds.split(",");
        int loginNotify = (isLoginNotify == null) ? 0 : isLoginNotify;
        for (String personIdStr : personIdArr) {
            if (!StringUtils.isNotBlank(personIdStr)) {
                continue;
            }
            EgDevicePersonBind bind = new EgDevicePersonBind();
            bind.setDeviceId(deviceId);
            bind.setPersonId(Integer.parseInt(personIdStr.trim()));
            bind.setIsLoginNotify(loginNotify);
            egDevicePersonBindMapper.insert(bind);
        }
    }
}
