package com.cmvr.evaluation.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cmvr.common.exception.GlobalException;
import com.cmvr.common.utils.http.CallAPIUtil;
import com.cmvr.evaluation.mapper.AeEvaluationMapper;
import com.cmvr.evaluation.model.domain.AeEvaluation;
import com.cmvr.evaluation.service.IAeEvaluationService;
import com.cmvr.llm.config.APIProperties;
import com.cmvr.test.enums.ActionEnum;
import com.cmvr.test.enums.RunModeEnum;
import com.cmvr.test.model.domain.TeNodeInst;
import com.cmvr.test.model.vo.TeFlowViewVO;
import com.cmvr.test.service.ITeNodeInstService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class AeEvaluationServiceImpl extends ServiceImpl<AeEvaluationMapper, AeEvaluation> implements IAeEvaluationService {

    private final ITeNodeInstService teNodeInstService;

    private final APIProperties apiProperties;
    private final StringRedisTemplate redisTemplate;

    @Override
    public void executeEvaluation(AeEvaluation evaluation) {
        String aeType = evaluation.getAeType();
        if (aeType.equals(RunModeEnum.VI_PROJECT.name())) {
            // 语音交互评估
            // 查询流程执行记录
            TeFlowViewVO teFlowViewVO = new TeFlowViewVO();
            teFlowViewVO.setInstId(evaluation.getInstId());
            teFlowViewVO.setItemId(evaluation.getItemId());

            List<TeNodeInst> view = teNodeInstService.view(teFlowViewVO);

            // 解析 VI_SCHEME 参数
            TeNodeInst viSchemeInst = view.stream()
                    .filter(e -> ActionEnum.VI_SCHEME.getAction().equals(e.getAction()))
                    .findFirst()
                    .orElseThrow(() -> new IllegalStateException("未找到 VI_SCHEME 节点"));

            JSONObject paramsOut = JSONObject.parseObject(viSchemeInst.getParamsOut());

            Integer sceneType = paramsOut.getInteger("sceneType");

            // 唤醒语料
            JSONObject wakeCorpus = paramsOut.getJSONObject("wakeCorpus");
            String wakeContent = wakeCorpus != null ? wakeCorpus.getString("textContent") : null;

            // 测试语料
            JSONArray testCorpusArray = paramsOut.getJSONArray("testCorpus");

            // 构建评估任务列表
            List<AeEvaluation> evaluations = new LinkedList<>();

            switch (sceneType) {

                // 场景 1：唤醒
                case 1: {
                    String audioUrl = extractAudioUrl(view);
                    String videoUrl = extractVideoUrl(view);
                    AeEvaluation eval = new AeEvaluation();
                    BeanUtil.copyProperties(evaluation, eval);
                    eval.setAeId(IdUtil.fastSimpleUUID());
                    eval.setStatus(0);           // 待评估
                    eval.setAvContent(wakeContent);
                    eval.setAudioPath(audioUrl);
                    eval.setVideoPath(videoUrl);
                    evaluations.add(eval);
                    break;
                }

                // 场景 2：单次对话（一层循环）
                case 2: {

                    view.stream()
                            .filter(e -> e.getAction().equals(ActionEnum.CAMERA_RECORDING_STOP.getAction()))
                            .map(x -> JSONObject.parseObject(x.getParamsOut()).getJSONObject("videoUrl").getString("videoUrl"))
                            .collect(Collectors.toList())
                            .forEach(System.out::println);

                    Map<String, List<TeNodeInst>> iterationMap = buildSingleIterationMap(view);

                    for (Map.Entry<String, List<TeNodeInst>> entry : iterationMap.entrySet()) {

                        String iterationKey = entry.getKey();      // "1" / "2" / ...
                        List<TeNodeInst> nodeList = entry.getValue();

                        int index = Integer.parseInt(iterationKey) - 1;
                        JSONObject corpus = testCorpusArray.getJSONObject(index);

                        String content = StrUtil.join(", ",
                                wakeContent,
                                corpus.getString("textContent")
                        );

                        String audioUrl = extractAudioUrl(nodeList);
                        String videoUrl = extractVideoUrl(nodeList);

                        AeEvaluation eval = new AeEvaluation();
                        BeanUtil.copyProperties(evaluation, eval);
                        eval.setAeId(IdUtil.fastSimpleUUID());
                        eval.setStatus(0);
                        eval.setAvContent(content);
                        eval.setAudioPath(audioUrl);
                        eval.setVideoPath(videoUrl);

                        evaluations.add(eval);
                    }
                    break;
                }

                // 场景 3：连续对话（嵌套循环）
                case 3: {

                    Map<String, List<TeNodeInst>> ContinuousIterationMap = buildContinuousIterationMap(view);
                    for (Map.Entry<String, List<TeNodeInst>> entry : ContinuousIterationMap.entrySet()) {

                        String key = entry.getKey();
                        List<TeNodeInst> value = entry.getValue();

                        // 每一个 outer iteration 代表一次完整连续对话
                        StringBuilder contentBuilder = new StringBuilder(wakeContent);


                        int corpusIndex = Integer.parseInt(key) - 1;
                        JSONArray corpus = testCorpusArray.getJSONArray(corpusIndex);

                        String corpusText = corpus.stream()
                                .filter(Objects::nonNull)
                                .map(obj -> ((JSONObject) obj).getString("textContent"))
                                .filter(StrUtil::isNotEmpty)
                                .collect(Collectors.joining(", "));

                        if (StrUtil.isNotEmpty(corpusText)) {
                            contentBuilder.append(", ").append(corpusText);
                        }

                        String audioUrl = extractAudioUrl(value);
                        String videoUrl = extractVideoUrl(value);

                        AeEvaluation eval = new AeEvaluation();
                        BeanUtil.copyProperties(evaluation, eval);
                        eval.setAeId(IdUtil.fastSimpleUUID());
                        eval.setStatus(0);
                        eval.setAvContent(contentBuilder.toString());
                        eval.setAudioPath(audioUrl);
                        eval.setVideoPath(videoUrl);

                        evaluations.add(eval);
                    }
                    break;
                }

                default:
                    throw new IllegalArgumentException("未知 sceneType：" + sceneType);
            }

            try {
                // 入库
                this.saveBatch(evaluations);

                // 提交评估
                for (AeEvaluation e : evaluations) {
                    redisTemplate.opsForList()
                            .rightPush("ae:evaluation:queue", JSON.toJSONString(e));
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else if (aeType.equals(RunModeEnum.TI_PROJECT.name())) {


        } else {
            throw new GlobalException("错误的评估任务类型！仅支持语音交互和触控交互！");
        }

    }

    public void runEvaluation(AeEvaluation evaluation) {
        LambdaUpdateWrapper<AeEvaluation> wrapper = Wrappers.lambdaUpdate();
        wrapper.eq(AeEvaluation::getAeId, evaluation.getAeId())
                .eq(AeEvaluation::getStatus, 0)
                .set(AeEvaluation::getStatus, 1);

        this.update(wrapper);
        // 构建评估请求
        Map<String, String> body = new HashMap<>();
        body.put("aeId", evaluation.getAeId());
        body.put("audioPath", evaluation.getAudioPath());
        body.put("videoPath", evaluation.getVideoPath());
        body.put("content", evaluation.getAvContent());
        body.put("aeType", evaluation.getAeType());
        HttpResponse httpResponse = CallAPIUtil.doPost(apiProperties.getEvaluation(), null, body);
        if (httpResponse.getStatus() != 200) {
            String responseBody = httpResponse.body();
            LambdaUpdateWrapper<AeEvaluation> wrapper1 = Wrappers.lambdaUpdate();
            wrapper1.eq(AeEvaluation::getAeId, evaluation.getAeId())
                    .eq(AeEvaluation::getStatus, 1)
                    .set(AeEvaluation::getStatus, 4)
                    .set(AeEvaluation::getResult, responseBody);

            this.update(wrapper1);
        }
    }


    @Override
    public List<AeEvaluation> queryEvaluation(String instId) {
        LambdaQueryWrapper<AeEvaluation> wrapper = Wrappers.lambdaQuery(AeEvaluation.class);
        wrapper.eq(AeEvaluation::getInstId, instId);
        return this.list(wrapper);
    }

    @Override
    public List<AeEvaluation> queryEvaluationByProjectId(String projectId) {
        LambdaQueryWrapper<AeEvaluation> wrapper = Wrappers.lambdaQuery(AeEvaluation.class);
        wrapper.eq(AeEvaluation::getTaskId, projectId);
        return this.list(wrapper);
    }

    @Override
    public boolean isAllEvaluationsFinished(String instId) {
        long total = this.count(
                Wrappers.lambdaQuery(AeEvaluation.class)
                        .eq(AeEvaluation::getInstId, instId)
        );

        if (total == 0) {
            return false;
        }

        long finished = this.count(
                Wrappers.lambdaQuery(AeEvaluation.class)
                        .eq(AeEvaluation::getInstId, instId)
                        .ge(AeEvaluation::getStatus, 2)
        );

        return finished == total;
    }

    private Map<String, List<TeNodeInst>> buildSingleIterationMap(List<TeNodeInst> view) {
        return view.stream()
                .filter(e -> StrUtil.isNotEmpty(e.getIteration()))
                .collect(Collectors.groupingBy(
                        TeNodeInst::getIteration,
                        LinkedHashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.stream()
                                        .sorted(Comparator.comparing(TeNodeInst::getId))
                                        .collect(Collectors.toList())
                        )
                ));
    }

    private Map<String, List<TeNodeInst>> buildContinuousIterationMap(List<TeNodeInst> view) {

        return view.stream()
                .filter(e -> StrUtil.isNotEmpty(e.getIteration()))
                // 只保留最外层 iteration（不包含子层）
                .filter(e -> !e.getIteration().contains("-"))
                .collect(Collectors.groupingBy(
                        TeNodeInst::getIteration,
                        LinkedHashMap::new,
                        Collectors.collectingAndThen(
                                Collectors.toList(),
                                list -> list.stream()
                                        .sorted(Comparator.comparing(TeNodeInst::getId))
                                        .collect(Collectors.toList())
                        )
                ));
    }

    private String extractAudioUrl(List<TeNodeInst> nodeList) {
        TeNodeInst microPhoneInst = nodeList.stream()
                .filter(e -> ActionEnum.MICROPHONE_STOP.getAction().equals(e.getAction()))
                .findFirst()
                .orElse(null);

        if (microPhoneInst == null) {
            return null;
        }

        JSONObject paramsOut = JSONObject.parseObject(microPhoneInst.getParamsOut());
        return paramsOut.getJSONObject("audioUrl").getString("audioUrl");
    }

    private String extractVideoUrl(List<TeNodeInst> nodeList) {
        TeNodeInst recordingInst = nodeList.stream()
                .filter(e -> ActionEnum.CAMERA_RECORDING_STOP.getAction().equals(e.getAction()))
                .findFirst()
                .orElse(null);

        if (recordingInst == null) {
            return null;
        }

        JSONObject paramsOut = JSONObject.parseObject(recordingInst.getParamsOut());
        return paramsOut.getJSONObject("videoUrl").getString("videoUrl");
    }
}
