package com.ycwl.basic.service.task.impl;

import cn.hutool.core.date.DateUtil;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.repository.MemberRelationRepository;
import com.ycwl.basic.utils.JacksonUtil;
import com.aliyuncs.facebody.model.v20191230.SearchFaceRequest;
import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.constant.FaceConstant;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.facebody.FaceBodyFactory;
import com.ycwl.basic.facebody.adapter.AliFaceBodyAdapter;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.facebody.enums.FaceBodyAdapterType;
import com.ycwl.basic.facebody.entity.SearchFaceResp;
import com.ycwl.basic.facebody.entity.SearchFaceResultItem;
import com.ycwl.basic.mapper.FaceDetectLogMapper;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.face.resp.FaceRespVO;

import com.ycwl.basic.model.pc.faceDetectLog.entity.FaceDetectLog;
import com.ycwl.basic.model.pc.faceDetectLog.resp.MatchLocalRecord;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
import com.ycwl.basic.model.pc.source.entity.SourceEntity;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;

import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.task.VideoPieceGetter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.aliyuncs.IAcsClient;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.HashSet;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME;

@Slf4j
@Service
public class TaskFaceServiceImpl implements TaskFaceService {
    @Autowired
    private FaceMapper faceMapper;
    @Autowired
    private FaceSampleMapper faceSampleMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private FaceDetectLogMapper logMapper;
    @Autowired
    private FaceRepository faceRepository;
    @Autowired
    private SourceMapper sourceMapper;
    @Autowired
    private OrderBiz orderBiz;

    @Autowired
    private ScenicRepository scenicRepository;
    @Autowired
    private DeviceRepository deviceRepository;
    @Autowired
    @Lazy
    private ScenicService scenicService;
    @Autowired
    private MemberRelationRepository memberRelationRepository;
    @Autowired
    private com.ycwl.basic.biz.FaceStatusManager faceStatusManager;

    private IAcsClient getClient() {
        AliFaceBodyAdapter use = (AliFaceBodyAdapter) FaceBodyFactory.use();
        return use.getClient().client();
    }

    @Override
    public SearchFaceRespVo searchFace(Long faceId) {
        FaceRespVO face = faceMapper.getById(faceId);
        if (face == null) {
            SearchFaceRespVo vo = new SearchFaceRespVo();
            vo.setSampleListIds(new ArrayList<>());
            return vo;
        }
        Long scenicId = face.getScenicId();
        ScenicConfigManager configManager = scenicRepository.getScenicConfigManager(scenicId);
        IFaceBodyAdapter faceBodyAdapter;
        if (configManager != null && configManager.getEnum("face_type", FaceBodyAdapterType.class) != null) {
            faceBodyAdapter = FaceBodyFactory.getAdapter(configManager.getEnum("face_type", FaceBodyAdapterType.class));
            faceBodyAdapter.loadConfig(JacksonUtil.parseObject(configManager.getString("face_config_json"), Map.class));
        } else {
            faceBodyAdapter = FaceBodyFactory.use();
        }
        SearchFaceRespVo respVo = searchFace(faceBodyAdapter, scenicId.toString(), face.getFaceUrl(), "系统定时任务检索");
        if (respVo != null) {
            FaceEntity faceEntity = new FaceEntity();
            faceEntity.setId(faceId);
            faceEntity.setMatchResult(respVo.getSearchResultJson());
            faceEntity.setFirstMatchRate(BigDecimal.valueOf(respVo.getFirstMatchRate()));
            faceEntity.setScore(respVo.getScore());
            faceEntity.setMatchSampleIds(StringUtils.join(respVo.getSampleListIds(), ","));
            faceMapper.update(faceEntity);
            faceRepository.clearFaceCache(faceId);
            List<Long> sampleListIds = respVo.getSampleListIds();
            if (sampleListIds != null && !sampleListIds.isEmpty()) {// 匹配原片：照片
                List<SourceEntity> sourceEntities = sourceMapper.listBySampleIds(sampleListIds);
                List<MemberSourceEntity> memberSourceEntityList = sourceEntities.stream().map(sourceEntity -> {
                    DeviceConfigManager deviceConfig = deviceRepository.getDeviceConfigManager(sourceEntity.getDeviceId());
                    MemberSourceEntity memberSourceEntity = new MemberSourceEntity();
                    memberSourceEntity.setScenicId(scenicId);
                    memberSourceEntity.setFaceId(faceEntity.getId());
                    memberSourceEntity.setMemberId(face.getMemberId());
                    memberSourceEntity.setSourceId(sourceEntity.getId());
                    memberSourceEntity.setType(sourceEntity.getType());
                    memberSourceEntity.setIsFree(0);
                    if (deviceConfig != null) {
                        if (sourceEntity.getType() == 1) {
                            if (Integer.valueOf(1).equals(deviceConfig.getInteger("video_free"))) {
                                memberSourceEntity.setIsFree(1);
                            }
                        } else if (sourceEntity.getType() == 2) {
                            if (Integer.valueOf(1).equals(deviceConfig.getInteger("image_free"))) {
                                memberSourceEntity.setIsFree(1);
                            }
                        }
                    }
                    return memberSourceEntity;
                }).collect(Collectors.toList());
                if (!memberSourceEntityList.isEmpty()) {
                    IsBuyRespVO isBuy = orderBiz.isBuy(face.getScenicId(), face.getMemberId(), faceEntity.getId(), memberSourceEntityList.getFirst().getType(), faceEntity.getId());
                    for (MemberSourceEntity memberSourceEntity : memberSourceEntityList) {
                        if (isBuy.isBuy()) { // 如果用户买过
                            memberSourceEntity.setIsBuy(1);
                        } else if (isBuy.isFree()) { // 全免费逻辑
                            memberSourceEntity.setIsBuy(1);
                        } else {
                            memberSourceEntity.setIsBuy(0);
                        }
                    }
                    // 过滤已存在的关联关系和无效的source引用，防止数据不一致
                    List<MemberSourceEntity> existingFiltered = sourceMapper.filterExistingRelations(memberSourceEntityList);
                    List<MemberSourceEntity> validFiltered = sourceMapper.filterValidSourceRelations(existingFiltered);
                    if (!validFiltered.isEmpty()) {
                        sourceMapper.addRelations(validFiltered);
                        log.debug("创建关联关系: faceId={}, 原始数量={}, 过滤后数量={}", 
                                  faceId, memberSourceEntityList.size(), validFiltered.size());
                    } else {
                        log.warn("没有有效的关联关系可创建: faceId={}, 原始数量={}", faceId, memberSourceEntityList.size());
                    }
                    memberRelationRepository.clearSCacheByFace(faceId);
                    faceStatusManager.invalidatePuzzleSourceVersion(faceId);
                    List<FaceSampleEntity> faceSampleList = faceRepository.getFaceSampleList(faceId);
                    List<Long> faceSampleIds = faceSampleList.stream()
                            .sorted(Comparator.comparing(FaceSampleEntity::getCreateAt).reversed())
                            .collect(Collectors.groupingBy(FaceSampleEntity::getDeviceId))
                            .entrySet()
                            .stream().flatMap(entry -> {
                                DeviceConfigManager deviceConfigManager = deviceRepository.getDeviceConfigManager(entry.getKey());
                                if (deviceConfigManager.getInteger("limit_video", 0) > 0) {
                                    return entry.getValue().subList(0, Math.min(entry.getValue().size(), deviceConfigManager.getInteger("limit_video", 0))).stream();
                                }
                                return entry.getValue().stream();
                            }).toList()
                            .stream().map(FaceSampleEntity::getId).toList();
                    VideoPieceGetter.Task task = new VideoPieceGetter.Task();
                    task.faceId = faceEntity.getId();
                    task.faceSampleIds = faceSampleIds;
                    task.memberId = face.getMemberId();
                    VideoPieceGetter.addTask(task);
                }
            }
        }
        return respVo;
    }

    @Override
    public SearchFaceRespVo searchFace(IFaceBodyAdapter adapter, String dbName, String faceUrl, String reason) {
        assureFaceDb(adapter, dbName);
        SearchFaceRequest request = new SearchFaceRequest();
        request.setDbName(dbName);
        request.setImageUrl(faceUrl);
        request.setLimit(200);
        FaceDetectLog logEntity = FaceDetectLog.quickCreate(reason, request);
        float threshold = 0;
        float lowThreshold = 100;
        ScenicConfigManager scenicConfig = null;
        if (StringUtils.isNumeric(dbName)) {
            scenicConfig = scenicRepository.getScenicConfigManager(Long.valueOf(dbName));
            if (scenicConfig != null) {
                if (scenicConfig.getFloat("face_score_threshold") != null) {
                    threshold = scenicConfig.getFloat("face_score_threshold") / 100F;
                }
                if (scenicConfig.getFloat("face_score_low_threshold") != null) {
                    lowThreshold = scenicConfig.getFloat("face_score_low_threshold") / 100F;
                }
            }
        } else if (StringUtils.isNumeric(dbName.replace(USER_FACE_DB_NAME, ""))) {
            Long scenicId = Long.valueOf(dbName.replace(USER_FACE_DB_NAME, ""));
            scenicConfig = scenicRepository.getScenicConfigManager(scenicId);
            if (scenicConfig != null) {
                if (scenicConfig.getFloat("face_score_threshold") != null) {
                    threshold = scenicConfig.getFloat("face_score_threshold") / 100F;
                }
                if (scenicConfig.getFloat("face_score_low_threshold") != null) {
                    lowThreshold = scenicConfig.getFloat("face_score_low_threshold") / 100F;
                }
            }
        }
        final float _threshold = threshold;
        List<Long> acceptFaceSampleIds;
        List<Long> allFaceSampleIds;
        try {
            SearchFaceResp response = adapter.searchFace(dbName, faceUrl);
            if (response == null) {
                return null;
            }
            logEntity.fillResponse(response);
            SearchFaceRespVo respVo = new SearchFaceRespVo();
            List<SearchFaceResultItem> records = response.getResult();
            respVo.setScore(response.getOriginalFaceScore());
            respVo.setSearchResultJson(JacksonUtil.toJSONString(records));
            logEntity.setMatchRawRecord(records);
            if (records.isEmpty()) {
                return respVo;
            }
            acceptFaceSampleIds = records.stream()
                    .sorted(Comparator.comparing(SearchFaceResultItem::getScore).reversed())
                    .filter(record -> record.getScore() > _threshold)
                    .map(SearchFaceResultItem::getExtData)
                    .filter(StringUtils::isNumeric)
                    .map(Long::valueOf)
                    .collect(Collectors.toList());
            float _lowThreshold = lowThreshold;
            boolean isLowThreshold = records.stream()
                    .anyMatch(record -> record.getScore() > _lowThreshold);
            respVo.setLowThreshold(isLowThreshold);
            allFaceSampleIds = records.stream()
                    .sorted(Comparator.comparing(SearchFaceResultItem::getScore).reversed())
                    .map(SearchFaceResultItem::getExtData)
                    .filter(StringUtils::isNumeric)
                    .map(Long::valueOf)
                    .collect(Collectors.toList());
            List<FaceSampleEntity> allFaceSampleList = faceSampleMapper.listByIds(allFaceSampleIds);
            // 按照allFaceSampleIds的顺序对allFaceSampleList进行排序
            Map<Long, Integer> idIndexMap = new HashMap<>();
            for (int i = 0; i < allFaceSampleIds.size(); i++) {
                idIndexMap.put(allFaceSampleIds.get(i), i);
            }
            allFaceSampleList.sort(Comparator.comparing(sample -> idIndexMap.get(sample.getId())));
            List<Long> finalAcceptedSampleIds = applySampleFilters(acceptFaceSampleIds, allFaceSampleList, scenicConfig);
            
            List<MatchLocalRecord> collect = new ArrayList<>();
            for (SearchFaceResultItem item : records) {
                MatchLocalRecord record = new MatchLocalRecord();
                record.setIdStr(item.getExtData());
                record.setFaceSampleId(Long.parseLong(item.getExtData()));
                if (StringUtils.isNumeric(item.getDbName())) {
                    Optional<FaceSampleEntity> optionalFse = allFaceSampleList.stream().filter(face -> face.getId().equals(Long.parseLong(item.getExtData()))).findAny();
                    if (optionalFse.isPresent()) {
                        DeviceEntity device = deviceRepository.getDevice(optionalFse.get().getDeviceId());
                        if (device != null) {
                            record.setDeviceName(device.getName());
                        }
                        record.setAccept(finalAcceptedSampleIds.contains(optionalFse.get().getId()));
                        record.setFaceUrl(optionalFse.get().getFaceUrl());
                        record.setShotDate(optionalFse.get().getCreateAt());
                    }
                } else {
                    record.setFaceUrl(getFaceUrl(record.getFaceSampleId()));
                }
                record.setScore(item.getScore());
                record.setMatched(item.getScore() > _threshold);
                collect.add(record);
            }
            logEntity.setMatchLocalRecord(JacksonUtil.toJSONString(collect));
            if (finalAcceptedSampleIds.isEmpty()) {
                respVo.setFirstMatchRate(0f);
                respVo.setSampleListIds(Collections.emptyList());
                return respVo;
            }
            respVo.setFirstMatchRate(response.getFirstMatchRate());
            respVo.setSampleListIds(finalAcceptedSampleIds);
            return respVo;
        } catch (Exception e) {
            logEntity.setMatchRawResult("识别错误，错误为：["+e.getLocalizedMessage()+"]");
            throw new BaseException(e.getMessage());
        } finally {
            logMapper.insert(logEntity);
        }
    }

    @Override
    public boolean deleteFaceSample(Long scenicId, String dbName, String entityId) {
        ScenicConfigManager configManager = scenicRepository.getScenicConfigManager(scenicId);
        IFaceBodyAdapter adapter = scenicService.getScenicFaceBodyAdapter(scenicId);
        log.info("删除{}人脸实体：{}", dbName, entityId);
        try {
            adapter.deleteFace(dbName, entityId);
            return true;
        } catch (Exception e) {
            log.error("删除人脸样本失败！", e);
            return false;
        }
    }

    @Override
    public boolean assureFaceDb(IFaceBodyAdapter faceBodyAdapter, String dbName) {
        if (redisTemplate.hasKey(FaceConstant.FACE_DB_NAME_PFX + dbName)) {
            return true;
        }
        try {
            if (!faceBodyAdapter.assureFaceDb(dbName)) {
                log.info("创建人脸库失败！");
                removeFaceDBCache(dbName);
                return false;
            }
            addFaceDBCache(dbName);
            return true;
        } catch (Exception e) {
            log.error("创建人脸库失败！", e);
            removeFaceDBCache(dbName);
            return false;
        }
    }

    public void addFaceDBCache(String dbName) {
        redisTemplate.opsForValue().set(FaceConstant.FACE_DB_NAME_PFX + dbName, "1", 2, TimeUnit.HOURS);
    }

    public Boolean removeFaceDBCache(String dbName) {
        return redisTemplate.delete(FaceConstant.FACE_DB_NAME_PFX + dbName);
    }

    public Boolean clearFaceDBCache() {
        return redisTemplate.delete(FaceConstant.FACE_DB_NAME_PFX + "*");
    }

    public String getFaceUrl(Long faceId) {
        if (faceId == null) {
            return null;
        }
        if (redisTemplate.hasKey(FaceConstant.FACE_USER_URL_PFX + faceId)) {
            return redisTemplate.opsForValue().get(FaceConstant.FACE_USER_URL_PFX + faceId);
        }
        FaceRespVO faceRespVO = faceMapper.getById(faceId);
        if (faceRespVO == null) {
            return null;
        }
        String faceUrl = faceRespVO.getFaceUrl();
        if (StringUtils.isNotBlank(faceUrl)) {
            addFaceUrlCache(faceId, faceUrl);
        }
        return faceUrl;
    }
    public void addFaceUrlCache(Long faceId, String faceUrl) {
        if (faceId == null) {
            return;
        }
        if (StringUtils.isBlank(faceUrl)) {
            return;
        }
        redisTemplate.opsForValue().set(FaceConstant.FACE_USER_URL_PFX + faceId, faceUrl, 3, TimeUnit.DAYS);
    }

    /**
     * 应用样本筛选逻辑
     * 包含时间范围筛选和未来可能的其他筛选策略
     * 
     * @param acceptedSampleIds 已接受的样本ID列表
     * @param allFaceSampleList 所有人脸样本实体列表
     * @param scenicConfig 景区配置，包含各种筛选策略的参数
     * @return 筛选后的样本ID列表
     */
    @Override
    public List<Long> applySampleFilters(List<Long> acceptedSampleIds,
                                         List<FaceSampleEntity> allFaceSampleList,
                                         ScenicConfigManager scenicConfig) {
        if (acceptedSampleIds == null || acceptedSampleIds.isEmpty()) {
            return acceptedSampleIds == null ? Collections.emptyList() : new ArrayList<>(acceptedSampleIds);
        }
        if (allFaceSampleList == null || allFaceSampleList.isEmpty()) {
            return new ArrayList<>(acceptedSampleIds);
        }

        Map<Long, FaceSampleEntity> sampleMap = allFaceSampleList.stream()
                .collect(Collectors.toMap(FaceSampleEntity::getId, sample -> sample, (a, b) -> a));

        List<Long> workingList = acceptedSampleIds.stream()
                .filter(sampleMap::containsKey)
                .collect(Collectors.toCollection(ArrayList::new));

        if (workingList.isEmpty()) {
            return Collections.emptyList();
        }

        Integer tourMinutes = scenicConfig != null ? scenicConfig.getInteger("tour_time") : null;
        if (tourMinutes != null && tourMinutes > 0) {
            workingList = filterSampleIdsByTimeRange(workingList, sampleMap, tourMinutes);
            log.debug("应用时间范围筛选：游览时间限制={}分钟，过滤后数量={}", tourMinutes, workingList.size());
        } else {
            log.debug("时间范围逻辑：景区未设置游览时间限制");
        }

        workingList = applyDevicePhotoLimit(workingList, sampleMap);

        log.debug("样本筛选完成：原始数量={}, 最终数量={}", acceptedSampleIds.size(), workingList.size());
        return new ArrayList<>(workingList);
    }

    private List<Long> filterSampleIdsByTimeRange(List<Long> acceptedSampleIds,
                                                   Map<Long, FaceSampleEntity> sampleMap,
                                                   int tourMinutes) {
        if (acceptedSampleIds == null || acceptedSampleIds.isEmpty()) {
            return Collections.emptyList();
        }
        FaceSampleEntity topMatchSample = acceptedSampleIds.stream()
                .map(sampleMap::get)
                .filter(Objects::nonNull)
                .max(Comparator.comparing(FaceSampleEntity::getCreateAt))
                .orElse(null);
        if (topMatchSample == null || topMatchSample.getCreateAt() == null) {
            log.warn("样本筛选逻辑：未找到匹配的人脸样本，acceptedIds: {}", acceptedSampleIds);
            return acceptedSampleIds;
        }

        Date startDate = DateUtil.offsetMinute(topMatchSample.getCreateAt(), -tourMinutes);
        Date endDate = DateUtil.offsetMinute(topMatchSample.getCreateAt(), 1);

        List<Long> result = new ArrayList<>();
        for (Long sampleId : acceptedSampleIds) {
            FaceSampleEntity sample = sampleMap.get(sampleId);
            if (sample == null || sample.getCreateAt() == null) {
                result.add(sampleId);
                continue;
            }
            Date createAt = sample.getCreateAt();
            if (createAt.after(startDate) && createAt.before(endDate)) {
                result.add(sampleId);
            }
        }

        log.info("时间范围逻辑：最高匹配：{}，时间范围：{}~{}，原样本数：{}，过滤后样本数：{}",
                topMatchSample.getId(), startDate, endDate, acceptedSampleIds.size(), result.size());
        return result;
    }

    private List<Long> applyDevicePhotoLimit(List<Long> acceptedSampleIds,
                                              Map<Long, FaceSampleEntity> sampleMap) {
        if (acceptedSampleIds == null || acceptedSampleIds.isEmpty()) {
            return Collections.emptyList();
        }

        Map<Long, List<FaceSampleEntity>> deviceSamplesMap = new LinkedHashMap<>();
        Set<Long> passthroughSampleIds = new LinkedHashSet<>();
        for (Long sampleId : acceptedSampleIds) {
            FaceSampleEntity sample = sampleMap.get(sampleId);
            if (sample == null || sample.getDeviceId() == null) {
                passthroughSampleIds.add(sampleId);
                continue;
            }
            deviceSamplesMap
                    .computeIfAbsent(sample.getDeviceId(), key -> new ArrayList<>())
                    .add(sample);
        }

        Map<Long, Integer> limitCache = new HashMap<>();
        Set<Long> retainedSampleIds = new LinkedHashSet<>(passthroughSampleIds);

        for (Map.Entry<Long, List<FaceSampleEntity>> entry : deviceSamplesMap.entrySet()) {
            Long deviceId = entry.getKey();
            List<FaceSampleEntity> deviceSamples = entry.getValue();
            List<Long> deviceSampleIds = deviceSamples.stream()
                    .map(FaceSampleEntity::getId)
                    .toList();

            Integer limitPhoto = limitCache.computeIfAbsent(deviceId, id -> {
                DeviceConfigManager deviceConfig = deviceRepository.getDeviceConfigManager(id);
                return deviceConfig != null ? deviceConfig.getInteger("limit_photo") : null;
            });

            List<Long> retainedForDevice;
            if (limitPhoto == null || limitPhoto <= 0) {
                retainedForDevice = deviceSampleIds;
                log.debug("设备照片限制：设备ID={}, 无限制，保留{}张照片", deviceId, deviceSampleIds.size());
            } else if (deviceSamples.size() > (limitPhoto + 2)) {
                retainedForDevice = processDeviceSamples(deviceSamples, limitPhoto, true);
                log.debug("设备照片限制：设备ID={}, 限制={}张, 原始{}张，去首尾后最终{}张",
                        deviceId, limitPhoto, deviceSamples.size(), retainedForDevice.size());
            } else if (deviceSamples.size() > (limitPhoto + 1)) {
                retainedForDevice = processDeviceSamples(deviceSamples, limitPhoto, false);
                log.debug("设备照片限制：设备ID={}, 限制={}张, 原始{}张，去尾部后最终{}张",
                        deviceId, limitPhoto, deviceSamples.size(), retainedForDevice.size());
            } else if (deviceSamples.size() > limitPhoto) {
                retainedForDevice = deviceSamples.stream()
                        .limit(limitPhoto)
                        .map(FaceSampleEntity::getId)
                        .toList();
                log.debug("设备照片限制：设备ID={}, 限制={}张, 原始{}张，取前{}张",
                        deviceId, limitPhoto, deviceSamples.size(), retainedForDevice.size());
            } else {
                retainedForDevice = deviceSampleIds;
                log.debug("设备照片限制：设备ID={}, 限制={}张, 原始{}张，无需筛选，保留全部",
                        deviceId, limitPhoto, deviceSamples.size());
            }

            retainedSampleIds.addAll(retainedForDevice);
        }

        List<Long> resultIds = new ArrayList<>(acceptedSampleIds.size());
        for (Long sampleId : acceptedSampleIds) {
            if (retainedSampleIds.contains(sampleId)) {
                resultIds.add(sampleId);
            }
        }

        log.info("设备照片数量限制筛选：原始样本数量={}, 筛选后数量={}",
                acceptedSampleIds.size(), resultIds.size());

        return resultIds;
    }

    /**
     * 处理设备样本，根据参数决定是否去掉首尾
     *
     * @param deviceSamples 设备样本列表
     * @param limitPhoto 限制数量
     * @param removeBoth 是否去掉首尾，true去掉首尾，false只去掉尾部
     * @return 处理后的样本ID列表
     */
    private List<Long> processDeviceSamples(List<FaceSampleEntity> deviceSamples, int limitPhoto, boolean removeBoth) {
        // 创建原始排序的索引映射，用于后续恢复排序
        Map<Long, Integer> originalIndexMap = new HashMap<>();
        for (int i = 0; i < deviceSamples.size(); i++) {
            originalIndexMap.put(deviceSamples.get(i).getId(), i);
        }

        // 按创建时间排序
        List<FaceSampleEntity> sortedByCreateTime = deviceSamples.stream()
                .sorted(Comparator.comparing(FaceSampleEntity::getCreateAt))
                .toList();

        // 根据参数决定去掉首尾还是只去掉尾部
        List<FaceSampleEntity> filteredSamples;
        if (removeBoth && sortedByCreateTime.size() > 2) {
            // 去掉首尾
            filteredSamples = sortedByCreateTime.subList(1, sortedByCreateTime.size() - 1);
        } else if (!removeBoth && sortedByCreateTime.size() > 1) {
            // 只去掉尾部（最新的）
            filteredSamples = sortedByCreateTime.subList(0, sortedByCreateTime.size() - 1);
        } else {
            // 样本数量不足，无法去掉
            filteredSamples = sortedByCreateTime;
        }

        // 恢复原排序并取限制数量
        List<FaceSampleEntity> finalSamples = filteredSamples.stream()
                .sorted(Comparator.comparing(sample -> originalIndexMap.get(sample.getId())))
                .limit(limitPhoto)
                .toList();

        return finalSamples.stream()
                .map(FaceSampleEntity::getId)
                .toList();
    }
}
