package com.ycwl.basic.integration.kafka.service;

import com.ycwl.basic.facebody.adapter.AliFaceBodyAdapter;
import com.ycwl.basic.facebody.adapter.BceFaceBodyAdapter;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.facebody.entity.AddFaceResp;
import com.ycwl.basic.facebody.entity.AliFaceBodyConfig;
import com.ycwl.basic.facebody.entity.BceFaceBodyConfig;
import com.ycwl.basic.integration.common.manager.DeviceConfigManager;
import com.ycwl.basic.integration.kafka.dto.FaceProcessingMessage;
import com.ycwl.basic.integration.kafka.scheduler.AccountFaceSchedulerManager;
import com.ycwl.basic.integration.kafka.scheduler.AccountSchedulerContext;
import com.ycwl.basic.mapper.FaceSampleAiCamMapper;
import com.ycwl.basic.mapper.FaceSampleMapper;
import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
import com.ycwl.basic.repository.DeviceRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.task.DynamicTaskGenerator;
import com.ycwl.basic.utils.JacksonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 人脸处理Kafka消费服务
 * 消费外部系统发送到zt-face topic的消息
 * <p>
 * 核心改进:
 * 1. 按账号(accessKeyId/appId)隔离线程池和QPS调度器
 * 2. 确保数据库优先写入,状态流转清晰
 * 3. 严格QPS控制,线程资源高效利用
 */
@Slf4j
@Service
@RequiredArgsConstructor
@ConditionalOnProperty(name = "kafka.enabled", havingValue = "true")
public class FaceProcessingKafkaService {

    private static final String ZT_FACE_TOPIC = "zt-face";
    private static final String ZT_AI_CAM_FACE_TOPIC = "zt-ai-cam-face";

    private final FaceSampleMapper faceSampleMapper;
    private final FaceSampleAiCamMapper faceSampleAiCamMapper;
    private final TaskFaceService taskFaceService;
    private final ScenicService scenicService;
    private final DeviceRepository deviceRepository;
    private final AccountFaceSchedulerManager schedulerManager;

    /**
     * 消费外部系统发送的人脸处理消息
     * 核心流程:
     * 1. 同步写入数据库 (最高优先级)
     * 2. 获取账号调度器上下文
     * 3. 提交到账号专属调度器队列
     */
    @KafkaListener(topics = ZT_FACE_TOPIC, containerFactory = "manualCommitKafkaListenerContainerFactory")
    public void processFaceMessage(String message, Acknowledgment ack) {
        Long faceSampleId = null;
        try {
            FaceProcessingMessage faceMessage = JacksonUtil.parseObject(message, FaceProcessingMessage.class);
            faceSampleId = faceMessage.getFaceSampleId();

            log.debug("接收人脸消息: scenicId={}, deviceId={}, faceSampleId={}",
                    faceMessage.getScenicId(), faceMessage.getDeviceId(), faceSampleId);

            // ========== 第一步: 同步写入数据库 (最高优先级) ==========
            boolean saved = saveFaceSample(faceMessage, faceSampleId);
            if (!saved) {
                log.error("数据库写入失败, 不提交识别任务, faceSampleId={}", faceSampleId);
                // 数据库写入失败,消费消息避免重复
                ack.acknowledge();
                return;
            }

            log.debug("数据库写入成功, faceSampleId={}, status=0", faceSampleId);

            // ========== 第二步: 获取账号调度器上下文 ==========
            AccountSchedulerContext schedulerCtx = getSchedulerContextForScenic(faceMessage.getScenicId());
            if (schedulerCtx == null) {
                log.error("无法获取调度器上下文, faceSampleId={}", faceSampleId);
                updateFaceSampleStatusSafely(faceSampleId, -1);
                ack.acknowledge();
                return;
            }

            // ========== 第三步: 提交到账号专属调度器 ==========
            boolean submitted = schedulerCtx.getScheduler().submit(() -> {
                processFaceRecognitionAsync(faceMessage);
            });

            if (submitted) {
                log.debug("任务已提交到调度器, account={}, cloudType={}, faceSampleId={}, schedulerQueue={}",
                        schedulerCtx.getAccountKey(),
                        schedulerCtx.getCloudType(),
                        faceSampleId,
                        schedulerCtx.getScheduler().getQueueSize());
            } else {
                log.error("调度器队列已满, account={}, faceSampleId={}",
                        schedulerCtx.getAccountKey(), faceSampleId);
                updateFaceSampleStatusSafely(faceSampleId, -1);
            }

            // 无论成功失败,都消费消息
            ack.acknowledge();

        } catch (Exception e) {
            log.error("处理人脸消息异常, faceSampleId={}", faceSampleId, e);
            if (faceSampleId != null) {
                updateFaceSampleStatusSafely(faceSampleId, -1);
            }
            ack.acknowledge();
        }
    }

    /**
     * 消费AI相机发送的人脸处理消息 (zt-ai-cam-face)
     * 逻辑与 zt-face 类似，但写入不同的表，且人脸库分组依据不同
     */
    @KafkaListener(topics = ZT_AI_CAM_FACE_TOPIC, containerFactory = "manualCommitKafkaListenerContainerFactory")
    public void processAiCamFaceMessage(String message, Acknowledgment ack) {
        Long faceSampleId = null;
        try {
            FaceProcessingMessage faceMessage = JacksonUtil.parseObject(message, FaceProcessingMessage.class);
            faceSampleId = faceMessage.getFaceSampleId();

            log.debug("接收AI相机人脸消息: scenicId={}, deviceId={}, faceSampleId={}",
                    faceMessage.getScenicId(), faceMessage.getDeviceId(), faceSampleId);

            // ========== 第一步: 同步写入数据库 (FaceSampleAiCam) ==========
            boolean saved = saveAiCamFaceSample(faceMessage, faceSampleId);
            if (!saved) {
                log.error("AI相机数据库写入失败, 不提交识别任务, faceSampleId={}", faceSampleId);
                ack.acknowledge();
                return;
            }

            log.debug("AI相机数据库写入成功, faceSampleId={}, status=0", faceSampleId);

            // ========== 第二步: 获取账号调度器上下文 ==========
            AccountSchedulerContext schedulerCtx = getSchedulerContextForScenic(faceMessage.getScenicId());
            if (schedulerCtx == null) {
                log.error("无法获取调度器上下文, faceSampleId={}", faceSampleId);
                updateAiCamFaceSampleStatusSafely(faceSampleId, -1);
                ack.acknowledge();
                return;
            }

            // ========== 第三步: 提交到账号专属调度器 ==========
            boolean submitted = schedulerCtx.getScheduler().submit(() -> {
                processAiCamFaceRecognitionAsync(faceMessage);
            });

            if (submitted) {
                log.debug("AI相机任务已提交到调度器, account={}, cloudType={}, faceSampleId={}, schedulerQueue={}",
                        schedulerCtx.getAccountKey(),
                        schedulerCtx.getCloudType(),
                        faceSampleId,
                        schedulerCtx.getScheduler().getQueueSize());
            } else {
                log.error("调度器队列已满, account={}, faceSampleId={}",
                        schedulerCtx.getAccountKey(), faceSampleId);
                updateAiCamFaceSampleStatusSafely(faceSampleId, -1);
            }

            ack.acknowledge();

        } catch (Exception e) {
            log.error("处理AI相机人脸消息异常, faceSampleId={}", faceSampleId, e);
            if (faceSampleId != null) {
                updateAiCamFaceSampleStatusSafely(faceSampleId, -1);
            }
            ack.acknowledge();
        }
    }

    /**
     * 根据景区获取对应的账号调度器上下文
     * 关键: 按 accessKeyId/appId 隔离,而非按云类型
     */
    private AccountSchedulerContext getSchedulerContextForScenic(Long scenicId) {
        try {
            // 获取景区的 adapter
            IFaceBodyAdapter adapter = scenicService.getScenicFaceBodyAdapter(scenicId);
            if (adapter == null) {
                log.error("景区 adapter 不存在, scenicId={}", scenicId);
                return null;
            }

            // 提取账号信息和QPS配置
            if (adapter instanceof AliFaceBodyAdapter aliAdapter) {
                AliFaceBodyConfig config = aliAdapter.getConfig();

                if (config == null || config.getAccessKeyId() == null) {
                    log.error("阿里云配置为空, scenicId={}", scenicId);
                    return null;
                }

                // 使用 accessKeyId 作为唯一标识
                String accountKey = config.getAccessKeyId();
                float qps = 2.0f; // 阿里云固定 2 QPS (AddFace操作)

                return schedulerManager.getOrCreateScheduler(accountKey, "ALI", qps);

            } else if (adapter instanceof BceFaceBodyAdapter baiduAdapter) {
                BceFaceBodyConfig config = baiduAdapter.getConfig();

                if (config == null || config.getAppId() == null) {
                    log.error("百度云配置为空, scenicId={}", scenicId);
                    return null;
                }

                // 使用 appId 作为唯一标识
                String accountKey = config.getAppId();
                float qps = config.getAddQps(); // 百度云可配置 QPS

                return schedulerManager.getOrCreateScheduler(accountKey, "BAIDU", qps);

            } else {
                log.error("未知的 adapter 类型: {}", adapter.getClass().getName());
                return null;
            }

        } catch (Exception e) {
            log.error("获取调度器上下文失败, scenicId={}", scenicId, e);
            return null;
        }
    }

    /**
     * 安全地更新人脸样本状态
     * 捕获所有异常,确保状态更新失败不影响主流程
     */
    private void updateFaceSampleStatusSafely(Long faceSampleId, Integer status) {
        if (faceSampleId == null) {
            return;
        }
        try {
            faceSampleMapper.updateStatus(faceSampleId, status);
            log.debug("状态更新成功: faceSampleId={}, status={}", faceSampleId, status);
        } catch (Exception e) {
            log.error("状态更新失败(非致命): faceSampleId={}, status={}", faceSampleId, status, e);
            // 不抛出异常,避免影响消息消费
        }
    }

    /**
     * 保存人脸样本数据到数据库
     * @param faceMessage 人脸处理消息
     * @param externalFaceId 外部传入的人脸ID
     * @return 是否保存成功
     */
    private boolean saveFaceSample(FaceProcessingMessage faceMessage, Long externalFaceId) {
        try {
            FaceSampleEntity faceSample = new FaceSampleEntity();
            faceSample.setId(externalFaceId); // 使用外部传入的ID
            faceSample.setScenicId(faceMessage.getScenicId());
            faceSample.setDeviceId(faceMessage.getDeviceId());
            faceSample.setStatus(0); // 初始状态
            faceSample.setFaceUrl(faceMessage.getFaceUrl());
            
            // 转换时间格式
            if (faceMessage.getShotTime() != null) {
                Date shotTime = faceMessage.getShotTime();
                faceSample.setCreateAt(shotTime);
            } else {
                faceSample.setCreateAt(new Date());
            }

            // 保存到数据库
            faceSampleMapper.add(faceSample);

            return true;
        } catch (Exception e) {
            log.error("保存人脸样本数据失败, 外部faceId: {}, scenicId: {}, deviceId: {}", 
                    externalFaceId, faceMessage.getScenicId(), faceMessage.getDeviceId(), e);
            return false;
        }
    }

    /**
     * 异步执行人脸识别处理逻辑
     * 对已保存的人脸样本进行识别处理
     */
    private void processFaceRecognitionAsync(FaceProcessingMessage message) {
        Long faceSampleId = message.getFaceSampleId();
        Long scenicId = message.getScenicId();

        try {
            // ========== 第一步: 更新状态为"处理中" ==========
            updateFaceSampleStatusSafely(faceSampleId, 1);
            log.debug("开始人脸识别, faceSampleId={}, status=1", faceSampleId);

            // ========== 第二步: 获取 adapter ==========
            IFaceBodyAdapter adapter = scenicService.getScenicFaceBodyAdapter(scenicId);
            if (adapter == null) {
                log.error("adapter 不存在, scenicId={}, faceSampleId={}", scenicId, faceSampleId);
                updateFaceSampleStatusSafely(faceSampleId, -1);
                return;
            }

            // ========== 第三步: 确保人脸数据库存在 ==========
            taskFaceService.assureFaceDb(adapter, scenicId.toString());

            // ========== 第四步: 调用 addFace (QPS已由调度器控制) ==========
            String faceUniqueId = faceSampleId.toString();
            AddFaceResp addFaceResp = adapter.addFace(
                    scenicId.toString(),
                    faceSampleId.toString(),
                    message.getFaceUrl(),
                    faceUniqueId
            );

            // ========== 第五步: 更新识别结果 ==========
            if (addFaceResp != null) {
                // 成功: 更新 score 和状态
                faceSampleMapper.updateScore(faceSampleId, addFaceResp.getScore());
                updateFaceSampleStatusSafely(faceSampleId, 2);

                log.info("人脸识别成功, faceSampleId={}, score={}, status=2",
                        faceSampleId, addFaceResp.getScore());

                // 可选: 触发预订任务
                Long deviceId = message.getDeviceId();
                DeviceConfigManager deviceConfig = deviceRepository.getDeviceConfigManager(deviceId);
                if (deviceConfig != null &&
                        Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) {
                    DynamicTaskGenerator.addTask(faceSampleId);
                }

            } else {
                // addFace 返回 null,识别失败
                log.warn("addFace 返回 null, faceSampleId={}", faceSampleId);
                updateFaceSampleStatusSafely(faceSampleId, -1);
            }

        } catch (Exception e) {
            // ========== 异常处理: 更新状态为失败 ==========
            log.error("人脸识别异常, faceSampleId={}", faceSampleId, e);
            updateFaceSampleStatusSafely(faceSampleId, -1);
        }
    }

    /**
     * 重试失败的人脸识别
     * 用于手动重试状态为-1的人脸样本
     *
     * @param faceSampleId 人脸样本ID
     * @return 是否成功提交重试任务
     */
    public boolean retryFaceRecognition(Long faceSampleId) {
        try {
            // 查询人脸样本信息
            FaceSampleEntity faceSample = faceSampleMapper.getEntity(faceSampleId);
            if (faceSample == null) {
                log.error("人脸样本不存在, faceSampleId: {}", faceSampleId);
                return false;
            }

            // 检查状态是否为失败状态(-1)
            if (faceSample.getStatus() != -1) {
                log.warn("人脸样本状态不是失败状态, 无需重试, faceSampleId: {}, status: {}",
                        faceSampleId, faceSample.getStatus());
                return false;
            }

            // 构造人脸处理消息
            FaceProcessingMessage message = FaceProcessingMessage.builder()
                    .faceSampleId(faceSample.getId())
                    .scenicId(faceSample.getScenicId())
                    .deviceId(faceSample.getDeviceId())
                    .faceUrl(faceSample.getFaceUrl())
                    .shotTime(faceSample.getCreateAt())
                    .createTime(new Date())
                    .source("retry-manual")
                    .build();

            // 获取账号调度器上下文
            AccountSchedulerContext schedulerCtx = getSchedulerContextForScenic(faceSample.getScenicId());
            if (schedulerCtx == null) {
                log.error("无法获取调度器上下文, faceSampleId={}", faceSampleId);
                return false;
            }

            // 提交到调度器进行异步处理
            boolean submitted = schedulerCtx.getScheduler().submit(() -> processFaceRecognitionAsync(message));

            if (submitted) {
                log.info("人脸识别重试任务已提交, faceSampleId={}, account={}, cloudType={}, schedulerQueue={}",
                        faceSampleId,
                        schedulerCtx.getAccountKey(),
                        schedulerCtx.getCloudType(),
                        schedulerCtx.getScheduler().getQueueSize());
                return true;
            } else {
                log.error("调度器队列已满,重试任务被拒绝, faceSampleId={}", faceSampleId);
                return false;
            }

        } catch (Exception e) {
            log.error("提交人脸识别重试任务失败, faceSampleId: {}", faceSampleId, e);
            return false;
        }
    }

    /**
     * 安全地更新AI相机人脸样本状态
     */
    private void updateAiCamFaceSampleStatusSafely(Long faceSampleId, Integer status) {
        if (faceSampleId == null) {
            return;
        }
        try {
            faceSampleAiCamMapper.updateStatus(faceSampleId, status);
            log.debug("AI相机样本状态更新成功: faceSampleId={}, status={}", faceSampleId, status);
        } catch (Exception e) {
            log.error("AI相机样本状态更新失败(非致命): faceSampleId={}, status={}", faceSampleId, status, e);
        }
    }

    /**
     * 保存AI相机人脸样本数据到数据库
     */
    private boolean saveAiCamFaceSample(FaceProcessingMessage faceMessage, Long externalFaceId) {
        try {
            FaceSampleEntity faceSample = new FaceSampleEntity();
            faceSample.setId(externalFaceId); // 使用外部传入的ID
            faceSample.setScenicId(faceMessage.getScenicId());
            faceSample.setDeviceId(faceMessage.getDeviceId());
            faceSample.setStatus(0); // 初始状态
            faceSample.setFaceUrl(faceMessage.getFaceUrl());
            
            if (faceMessage.getShotTime() != null) {
                faceSample.setCreateAt(faceMessage.getShotTime());
            } else {
                faceSample.setCreateAt(new Date());
            }

            faceSampleAiCamMapper.add(faceSample);

            return true;
        } catch (Exception e) {
            log.error("保存AI相机人脸样本数据失败, 外部faceId: {}, scenicId: {}, deviceId: {}", 
                    externalFaceId, faceMessage.getScenicId(), faceMessage.getDeviceId(), e);
            return false;
        }
    }

    /**
     * 异步执行AI相机人脸识别处理逻辑
     * 区别: 使用 deviceId 作为人脸库分组
     */
    private void processAiCamFaceRecognitionAsync(FaceProcessingMessage message) {
        Long faceSampleId = message.getFaceSampleId();
        Long scenicId = message.getScenicId();
        Long deviceId = message.getDeviceId();

        try {
            updateAiCamFaceSampleStatusSafely(faceSampleId, 1);
            log.debug("开始AI相机人脸识别, faceSampleId={}, status=1", faceSampleId);

            IFaceBodyAdapter adapter = scenicService.getScenicFaceBodyAdapter(scenicId);
            if (adapter == null) {
                log.error("adapter 不存在, scenicId={}, faceSampleId={}", scenicId, faceSampleId);
                updateAiCamFaceSampleStatusSafely(faceSampleId, -1);
                return;
            }

            // 使用 "AiCam" + deviceId 作为人脸库分组
            String dbName = "AiCam" + deviceId;
            taskFaceService.assureFaceDb(adapter, dbName);

            String faceUniqueId = faceSampleId.toString();
            // groupName 使用 deviceId
            AddFaceResp addFaceResp = adapter.addFace(
                    dbName,
                    faceSampleId.toString(),
                    message.getFaceUrl(),
                    faceUniqueId
            );

            if (addFaceResp != null) {
                faceSampleAiCamMapper.updateScore(faceSampleId, addFaceResp.getScore());
                updateAiCamFaceSampleStatusSafely(faceSampleId, 2);

                log.info("AI相机人脸识别成功, faceSampleId={}, score={}, status=2",
                        faceSampleId, addFaceResp.getScore());

                // 预订任务逻辑与原逻辑保持一致 (如果需要)
                DeviceConfigManager deviceConfig = deviceRepository.getDeviceConfigManager(deviceId);
                if (deviceConfig != null &&
                        Integer.valueOf(1).equals(deviceConfig.getInteger("enable_pre_book"))) {
                    DynamicTaskGenerator.addTask(faceSampleId);
                }

            } else {
                log.warn("addFace 返回 null, faceSampleId={}", faceSampleId);
                updateAiCamFaceSampleStatusSafely(faceSampleId, -1);
            }

        } catch (Exception e) {
            log.error("AI相机人脸识别异常, faceSampleId={}", faceSampleId, e);
            updateAiCamFaceSampleStatusSafely(faceSampleId, -1);
        }
    }
}