package com.ycwl.basic.face.pipeline.stages;

import com.ycwl.basic.face.pipeline.core.FaceMatchingContext;
import com.ycwl.basic.pipeline.annotation.StageConfig;
import com.ycwl.basic.pipeline.core.AbstractPipelineStage;
import com.ycwl.basic.pipeline.core.StageResult;
import com.ycwl.basic.pipeline.enums.StageOptionalMode;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.repository.DeviceRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 按设备照片数量限制筛选样本Stage
 * 负责根据设备配置的照片数量限制(limit_photo)筛选匹配样本
 *
 * 职责:
 * 1. 从context.faceSamples读取样本实体缓存
 * 2. 按设备ID分组
 * 3. 对每个设备,根据其limit_photo配置筛选样本:
 *    - 如果样本数 > limit_photo + 2: 按时间排序,去掉首尾,保留中间limit_photo张
 *    - 如果样本数 > limit_photo + 1: 按时间排序,去掉尾部,保留前limit_photo张
 *    - 如果样本数 > limit_photo: 保留前limit_photo张
 *    - 否则: 保留全部
 * 4. 更新context.sampleListIds
 *
 * 前置条件: context.faceSamples不为空 (由LoadMatchedSamplesStage加载)
 * 配置说明: limit_photo=0或null表示不限制数量
 */
@Slf4j
@Component
@StageConfig(
    stageId = "filter_by_device_photo_limit",
    optionalMode = StageOptionalMode.SUPPORT,
    description = "按设备照片数量限制筛选样本",
    defaultEnabled = true
)
public class FilterByDevicePhotoLimitStage extends AbstractPipelineStage<FaceMatchingContext> {

    @Autowired
    private DeviceRepository deviceRepository;

    @Override
    public String getName() {
        return "FilterByDevicePhotoLimit";
    }

    @Override
    protected boolean shouldExecuteByBusinessLogic(FaceMatchingContext context) {
        // 检查faceSamples是否为空
        List<FaceSampleEntity> faceSamples = context.getFaceSamples();
        if (faceSamples == null || faceSamples.isEmpty()) {
            log.debug("faceSamples为空,跳过设备照片限制筛选,faceId={}", context.getFaceId());
            return false;
        }
        return true;
    }

    @Override
    protected StageResult<FaceMatchingContext> doExecute(FaceMatchingContext context) {
        List<FaceSampleEntity> faceSamples = context.getFaceSamples();
        List<Long> sampleListIds = context.getSampleListIds();
        Long faceId = context.getFaceId();

        // 防御性检查：faceSamples为空
        if (faceSamples == null || faceSamples.isEmpty()) {
            log.debug("faceSamples为空,跳过设备照片限制筛选,faceId={}", faceId);
            return StageResult.skipped("faceSamples为空");
        }

        try {
            // 1. 构建样本ID到实体的映射
            Map<Long, FaceSampleEntity> sampleMap = faceSamples.stream()
                    .collect(Collectors.toMap(FaceSampleEntity::getId, sample -> sample, (a, b) -> a));

            // 2. 按设备ID分组
            Map<Long, List<FaceSampleEntity>> deviceSamplesMap = new LinkedHashMap<>();
            Set<Long> passthroughSampleIds = new LinkedHashSet<>();

            for (Long sampleId : sampleListIds) {
                FaceSampleEntity sample = sampleMap.get(sampleId);
                if (sample == null || sample.getDeviceId() == null) {
                    passthroughSampleIds.add(sampleId); // 无设备ID的样本直接保留
                    continue;
                }
                deviceSamplesMap
                        .computeIfAbsent(sample.getDeviceId(), key -> new ArrayList<>())
                        .add(sample);
            }

            // 3. 对每个设备应用照片数量限制
            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();

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

                List<Long> retainedForDevice = applyLimitForDevice(deviceId, deviceSamples, limitPhoto);
                retainedSampleIds.addAll(retainedForDevice);
            }

            // 4. 按原始顺序保留筛选后的样本ID
            List<Long> resultIds = sampleListIds.stream()
                    .filter(retainedSampleIds::contains)
                    .collect(Collectors.toList());

            // 5. 更新context
            context.setSampleListIds(resultIds);

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

            return StageResult.success(String.format("设备限制筛选: %d → %d",
                    sampleListIds.size(), resultIds.size()));

        } catch (Exception e) {
            log.error("设备照片数量限制筛选失败,faceId={}", faceId, e);
            // 筛选失败不影响主流程,返回降级
            return StageResult.degraded("设备照片数量限制筛选失败: " + e.getMessage());
        }
    }

    /**
     * 对单个设备的样本应用照片数量限制
     */
    private List<Long> applyLimitForDevice(Long deviceId, List<FaceSampleEntity> deviceSamples, Integer limitPhoto) {
        List<Long> deviceSampleIds = deviceSamples.stream()
                .map(FaceSampleEntity::getId)
                .collect(Collectors.toList());

        // 无限制或限制数量<=0,保留全部
        if (limitPhoto == null || limitPhoto <= 0) {
            log.debug("设备照片限制: 设备ID={}, 无限制, 保留{}张照片", deviceId, deviceSampleIds.size());
            return deviceSampleIds;
        }

        int sampleCount = deviceSamples.size();

        // 样本数 > limit_photo + 2: 按时间排序,去掉首尾
        if (sampleCount > (limitPhoto + 2)) {
            List<Long> retained = processDeviceSamples(deviceSamples, limitPhoto, true);
            log.debug("设备照片限制: 设备ID={}, 限制={}张, 原始{}张, 去首尾后最终{}张",
                    deviceId, limitPhoto, sampleCount, retained.size());
            return retained;
        }

        // 样本数 > limit_photo + 1: 按时间排序,去掉尾部
        if (sampleCount > (limitPhoto + 1)) {
            List<Long> retained = processDeviceSamples(deviceSamples, limitPhoto, false);
            log.debug("设备照片限制: 设备ID={}, 限制={}张, 原始{}张, 去尾部后最终{}张",
                    deviceId, limitPhoto, sampleCount, retained.size());
            return retained;
        }

        // 样本数 > limit_photo: 保留前limit_photo张
        if (sampleCount > limitPhoto) {
            List<Long> retained = deviceSamples.stream()
                    .limit(limitPhoto)
                    .map(FaceSampleEntity::getId)
                    .collect(Collectors.toList());
            log.debug("设备照片限制: 设备ID={}, 限制={}张, 原始{}张, 取前{}张",
                    deviceId, limitPhoto, sampleCount, retained.size());
            return retained;
        }

        // 样本数 <= limit_photo: 保留全部
        log.debug("设备照片限制: 设备ID={}, 限制={}张, 原始{}张, 无需筛选, 保留全部",
                deviceId, limitPhoto, sampleCount);
        return deviceSampleIds;
    }

    /**
     * 处理设备样本,根据参数决定是否去掉首尾
     *
     * @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))
                .collect(Collectors.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;
        }

        // 取前limitPhoto个
        List<FaceSampleEntity> limitedSamples = filteredSamples.stream()
                .limit(limitPhoto)
                .collect(Collectors.toList());

        // 按原始顺序排序
        List<Long> resultIds = limitedSamples.stream()
                .sorted(Comparator.comparing(sample -> originalIndexMap.get(sample.getId())))
                .map(FaceSampleEntity::getId)
                .collect(Collectors.toList());

        return resultIds;
    }
}
