package com.ycwl.basic.service.pc.orchestrator;

import com.ycwl.basic.biz.OrderBiz;
import com.ycwl.basic.exception.BaseException;
import com.ycwl.basic.facebody.adapter.IFaceBodyAdapter;
import com.ycwl.basic.integration.common.manager.ScenicConfigManager;
import com.ycwl.basic.mapper.FaceMapper;
import com.ycwl.basic.mapper.SourceMapper;
import com.ycwl.basic.model.pc.face.entity.FaceEntity;
import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
import com.ycwl.basic.repository.FaceRepository;
import com.ycwl.basic.repository.MemberRelationRepository;
import com.ycwl.basic.repository.ScenicRepository;
import com.ycwl.basic.service.pc.ScenicService;
import com.ycwl.basic.service.pc.helper.FaceMetricsRecorder;
import com.ycwl.basic.service.pc.helper.ScenicConfigFacade;
import com.ycwl.basic.service.pc.processor.BuyStatusProcessor;
import com.ycwl.basic.service.pc.processor.FaceRecoveryStrategy;
import com.ycwl.basic.service.pc.processor.SourceRelationProcessor;
import com.ycwl.basic.service.pc.processor.VideoRecreationHandler;
import com.ycwl.basic.service.task.TaskFaceService;
import com.ycwl.basic.service.task.TaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 人脸匹配流程编排器
 * 将 matchFaceId 的复杂流程拆分为清晰的步骤，每个步骤负责单一职责
 *
 * 主要步骤：
 * 1. 数据准备 - 获取人脸信息、配置、适配器
 * 2. 人脸识别 - 执行人脸搜索和补救逻辑
 * 3. 结果更新 - 更新人脸实体信息
 * 4. 源文件关联 - 处理匹配到的源文件
 * 5. 业务处理 - 免费逻辑、购买状态、任务创建
 * 6. 数据持久化 - 保存关联关系
 *
 * @author Claude
 * @since 2025-10-31
 */
@Slf4j
@Component
public class FaceMatchingOrchestrator {

    @Autowired
    private FaceRepository faceRepository;
    @Autowired
    private FaceMapper faceMapper;
    @Autowired
    private ScenicRepository scenicRepository;
    @Autowired
    private ScenicService scenicService;
    @Autowired
    private TaskFaceService taskFaceService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private SourceMapper sourceMapper;
    @Autowired
    private MemberRelationRepository memberRelationRepository;

    // 辅助类和处理器
    @Autowired
    private FaceMetricsRecorder metricsRecorder;
    @Autowired
    private ScenicConfigFacade scenicConfigFacade;
    @Autowired
    private FaceRecoveryStrategy faceRecoveryStrategy;
    @Autowired
    private SourceRelationProcessor sourceRelationProcessor;
    @Autowired
    private BuyStatusProcessor buyStatusProcessor;
    @Autowired
    private VideoRecreationHandler videoRecreationHandler;

    /**
     * 编排人脸匹配的完整流程
     *
     * @param faceId 人脸ID
     * @param isNew  是否新用户
     * @return 人脸搜索结果
     */
    public SearchFaceRespVo orchestrateMatching(Long faceId, boolean isNew) {
        if (faceId == null) {
            throw new IllegalArgumentException("faceId 不能为空");
        }

        // 步骤1: 数据准备
        MatchingContext context = prepareMatchingContext(faceId, isNew);
        if (context == null) {
            return null;
        }

        // 记录识别次数
        metricsRecorder.recordRecognitionCount(faceId);

        try {
            // 步骤2: 人脸识别
            SearchFaceRespVo searchResult = executeFaceRecognition(context);
            if (searchResult == null) {
                log.warn("人脸识别返回结果为空，faceId={}", faceId);
                throw new BaseException("人脸识别失败，请换一张试试把~");
            }

            // 执行补救逻辑
            searchResult = faceRecoveryStrategy.executeFaceRecoveryLogic(
                    searchResult, context.scenicConfig, context.faceBodyAdapter, context.face.getScenicId());

            // 步骤3: 更新人脸结果
            updateFaceResult(context.face, searchResult, faceId);

            // 步骤4-6: 处理源文件关联和业务逻辑
            processSourceRelations(context, searchResult, faceId, isNew);

            return searchResult;

        } catch (BaseException e) {
            throw e;
        } catch (Exception e) {
            log.error("人脸匹配流程异常，faceId={}", faceId, e);
            throw new BaseException("人脸匹配处理失败");
        }
    }

    /**
     * 步骤1: 准备匹配上下文
     * 获取人脸信息、景区配置、人脸识别适配器等必要数据
     */
    private MatchingContext prepareMatchingContext(Long faceId, boolean isNew) {
        FaceEntity face = faceRepository.getFace(faceId);
        if (face == null) {
            log.warn("人脸不存在，faceId: {}", faceId);
            return null;
        }

        // 人工选择的无需重新匹配（新用户除外）
        if (!isNew && Integer.valueOf(1).equals(face.getIsManual())) {
            log.info("人工选择的，无需匹配，faceId: {}", faceId);
            return null;
        }

        log.debug("开始人脸匹配：faceId={}, isNew={}", faceId, isNew);

        ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(face.getScenicId());
        IFaceBodyAdapter faceBodyAdapter = scenicService.getScenicFaceBodyAdapter(face.getScenicId());

        if (faceBodyAdapter == null) {
            log.error("无法获取人脸识别适配器，scenicId: {}", face.getScenicId());
            throw new BaseException("人脸识别服务不可用，请稍后再试");
        }

        MatchingContext context = new MatchingContext();
        context.face = face;
        context.scenicConfig = scenicConfig;
        context.faceBodyAdapter = faceBodyAdapter;
        return context;
    }

    /**
     * 步骤2: 执行人脸识别
     * 调用人脸识别服务进行人脸搜索
     */
    private SearchFaceRespVo executeFaceRecognition(MatchingContext context) {
        try {
            return taskFaceService.searchFace(
                    context.faceBodyAdapter,
                    String.valueOf(context.face.getScenicId()),
                    context.face.getFaceUrl(),
                    "人脸识别");
        } catch (Exception e) {
            log.error("人脸识别服务调用失败，faceId={}, scenicId={}",
                    context.face.getId(), context.face.getScenicId(), e);
            throw new BaseException("人脸识别失败，请换一张试试把~");
        }
    }

    /**
     * 步骤3: 更新人脸结果
     * 保存人脸匹配结果到数据库
     */
    private void updateFaceResult(FaceEntity originalFace, SearchFaceRespVo searchResult, Long faceId) {
        try {
            FaceEntity faceEntity = new FaceEntity();
            faceEntity.setId(faceId);
            faceEntity.setScore(searchResult.getScore());
            faceEntity.setMatchResult(searchResult.getSearchResultJson());

            if (searchResult.getFirstMatchRate() != null) {
                faceEntity.setFirstMatchRate(BigDecimal.valueOf(searchResult.getFirstMatchRate()));
            }

            if (searchResult.getSampleListIds() != null) {
                faceEntity.setMatchSampleIds(searchResult.getSampleListIds().stream()
                        .map(String::valueOf)
                        .collect(Collectors.joining(",")));
            }

            faceEntity.setCreateAt(new Date());
            faceEntity.setScenicId(originalFace.getScenicId());
            faceEntity.setMemberId(originalFace.getMemberId());
            faceEntity.setFaceUrl(originalFace.getFaceUrl());

            faceMapper.update(faceEntity);
            faceRepository.clearFaceCache(faceEntity.getId());

            log.debug("人脸结果更新成功：faceId={}, score={}, sampleCount={}",
                    faceId, searchResult.getScore(),
                    searchResult.getSampleListIds() != null ? searchResult.getSampleListIds().size() : 0);
        } catch (Exception e) {
            log.error("更新人脸结果失败，faceId={}", faceId, e);
            throw new BaseException("保存人脸识别结果失败");
        }
    }

    /**
     * 步骤4-6: 处理源文件关联和业务逻辑
     * 包括：源文件关联、免费逻辑、购买状态、视频重切、任务创建、数据持久化
     */
    private void processSourceRelations(MatchingContext context, SearchFaceRespVo searchResult,
                                        Long faceId, boolean isNew) {
        List<Long> sampleListIds = searchResult.getSampleListIds();

        if (sampleListIds == null || sampleListIds.isEmpty()) {
            log.warn("人脸匹配无结果：faceId={}", faceId);

            // 记录低阈值检测
            if (searchResult.isLowThreshold()) {
                metricsRecorder.recordLowThreshold(faceId);
                log.debug("触发低阈值检测，记录faceId: {}", faceId);
            }
            return;
        }

        try {
            // 4. 源文件关联：处理匹配到的源文件
            List<MemberSourceEntity> memberSourceEntityList =
                    sourceRelationProcessor.processMemberSources(sampleListIds, context.face);

            if (memberSourceEntityList.isEmpty()) {
                log.warn("未找到有效的源文件，faceId={}", faceId);
                return;
            }

            // 5. 业务逻辑处理
            processBusinessLogic(context, memberSourceEntityList, faceId, sampleListIds, isNew);

            // 6. 数据持久化
            persistSourceRelations(faceId, memberSourceEntityList);

            // 7. 任务创建
            createTaskIfNeeded(context.face.getScenicId(), faceId);

            log.info("人脸匹配完成：faceId={}, 匹配样本数={}, 关联源文件数={}",
                    faceId, sampleListIds.size(), memberSourceEntityList.size());

        } catch (Exception e) {
            log.error("处理源文件关联失败，faceId={}", faceId, e);
            // 源文件关联失败不影响主流程，记录错误但不抛出异常
        }
    }

    /**
     * 步骤5: 业务逻辑处理
     * 处理免费逻辑、购买状态、视频重切
     */
    private void processBusinessLogic(MatchingContext context, List<MemberSourceEntity> memberSourceEntityList,
                                      Long faceId, List<Long> sampleListIds, boolean isNew) {
        // 免费逻辑
        List<Long> freeSourceIds = sourceRelationProcessor.processFreeSourceLogic(
                memberSourceEntityList, context.face.getScenicId(), isNew);

        // 购买状态
        buyStatusProcessor.processBuyStatus(
                memberSourceEntityList, freeSourceIds,
                context.face.getMemberId(), context.face.getScenicId(), faceId);

        // 视频重切
        videoRecreationHandler.handleVideoRecreation(
                context.face.getScenicId(), memberSourceEntityList,
                faceId, context.face.getMemberId(), sampleListIds, isNew);
    }

    /**
     * 步骤6: 数据持久化
     * 过滤并保存源文件关联关系
     */
    private void persistSourceRelations(Long faceId, List<MemberSourceEntity> memberSourceEntityList) {
        // 过滤已存在的关联关系和无效的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);
    }

    /**
     * 步骤7: 任务创建
     * 根据配置决定是否自动创建任务
     */
    private void createTaskIfNeeded(Long scenicId, Long faceId) {
        if (!scenicConfigFacade.isFaceSelectFirst(scenicId)) {
            taskService.autoCreateTaskByFaceId(faceId);
        } else {
            log.debug("景区配置 face_select_first=true，跳过自动创建任务：faceId={}", faceId);
        }
    }

    /**
     * 匹配上下文
     * 封装匹配过程中需要的所有上下文信息
     */
    private static class MatchingContext {
        FaceEntity face;
        ScenicConfigManager scenicConfig;
        IFaceBodyAdapter faceBodyAdapter;
    }
}
