package com.tashow.cloud.ai.service.model;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelAnalysisResultVO;
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelDifferenceVO;
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelPageReqVO;
import com.tashow.cloud.ai.controller.admin.model.vo.AiModelSaveReqVO;
import com.tashow.cloud.ai.controller.admin.model.vo.AiSampleDetailVO;
import com.tashow.cloud.ai.dal.dataobject.aisample.AiSampleDO;
import com.tashow.cloud.ai.dal.dataobject.aisample.AiSampleTagDO;
import com.tashow.cloud.ai.dal.dataobject.aisample.AiSampleTagGroupDO;
import com.tashow.cloud.ai.dal.dataobject.aisample.AiSampleTagRelateDO;
import com.tashow.cloud.ai.dal.dataobject.model.AiModelDO;
import com.tashow.cloud.ai.dal.dataobject.model.AiModelSampleRelateDO;
import com.tashow.cloud.ai.dal.mysql.aisample.AiSampleMapper;
import com.tashow.cloud.ai.dal.mysql.aisample.AiSampleTagGroupMapper;
import com.tashow.cloud.ai.dal.mysql.aisample.AiSampleTagMapper;
import com.tashow.cloud.ai.dal.mysql.aisample.AiSampleTagRelateMapper;
import com.tashow.cloud.ai.dal.mysql.model.AiModelMapper;
import com.tashow.cloud.ai.dal.mysql.model.AiModelSampleRelateMapper;
import com.tashow.cloud.common.pojo.PageResult;
import com.tashow.cloud.common.util.object.BeanUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@Validated
@Slf4j
public class AiModelServiceImpl implements AiModelService {

    @Resource
    private AiModelMapper modelMapper;
    @Resource
    private AiModelSampleRelateMapper modelSampleRelateMapper;
    @Resource
    private AiSampleMapper sampleMapper;
    @Resource
    private AiSampleTagRelateMapper sampleTagRelateMapper;
    @Resource
    private AiSampleTagMapper sampleTagMapper;
    @Resource
    private AiSampleTagGroupMapper sampleTagGroupMapper;

    @Value("${translate-server}")
    private String translateServer;
    @Value("${file-server}")
    private String fileServer;

    @Override
    public Long createModel(AiModelSaveReqVO createReqVO) {
        AiModelDO model = BeanUtils.toBean(createReqVO, AiModelDO.class);
        modelMapper.insert(model);
        return model.getId();
    }

    @Override
    public void updateModel(AiModelSaveReqVO updateReqVO) {
        modelMapper.updateById(BeanUtils.toBean(updateReqVO, AiModelDO.class));
    }

    @Override
    public void deleteModel(Long id) {
        modelMapper.deleteById(id);
    }

    @Override
    public List<AiModelDO> getEnabledModels() {
        return modelMapper.selectList(new LambdaQueryWrapper<AiModelDO>().eq(AiModelDO::getStatus, 1));
    }

    @Override
    public PageResult<AiModelDO> getModelPage(AiModelPageReqVO pageReqVO) {
        return modelMapper.selectPage(pageReqVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void referenceSamples(Long modelId, List<Long> sampleIds) {
        modelSampleRelateMapper.delete(new LambdaQueryWrapper<AiModelSampleRelateDO>()
                .eq(AiModelSampleRelateDO::getModelId, modelId));
        if (CollUtil.isEmpty(sampleIds)) {
            return;
        }
        List<AiModelSampleRelateDO> relates = sampleIds.stream()
                .map(sampleId -> AiModelSampleRelateDO.builder().modelId(modelId).sampleId(sampleId).build())
                .toList();
        modelSampleRelateMapper.insertBatch(relates);
    }

    @Override
    public List<AiSampleDO> getModelSamples(Long modelId) {
        List<Long> sampleIds = modelSampleRelateMapper.selectList(new LambdaQueryWrapper<AiModelSampleRelateDO>()
                        .eq(AiModelSampleRelateDO::getModelId, modelId))
                .stream().map(AiModelSampleRelateDO::getSampleId).toList();
        return sampleMapper.selectBatchIds(sampleIds);
    }

    @Override
    public AiModelAnalysisResultVO analyzeModel(List<Long> sampleIds, List<Long> modelIds) {
        if (CollUtil.isEmpty(sampleIds) || CollUtil.isEmpty(modelIds)) {
            return AiModelAnalysisResultVO.builder().samples(List.of()).build();
        }

        List<AiModelAnalysisResultVO.SampleAnalysis> samples = new ArrayList<>();
        for (Long sampleId : sampleIds) {
            AiSampleDO sample = sampleMapper.selectById(sampleId);
            if (sample == null) {
                continue;
            }

            List<AiSampleTagDO> enumTags = getEnumTagsForSample(sampleId);
            String enumTagStr = enumTags.stream().map(AiSampleTagDO::getTagName).collect(Collectors.joining(","));

            List<AiModelAnalysisResultVO.ModelAnalysisResult> modelResults = modelIds.stream()
                    .map(modelRefId -> buildModelAnalysis(sample, enumTags, modelRefId))
                    .filter(Objects::nonNull)
                    .toList();

            samples.add(AiModelAnalysisResultVO.SampleAnalysis.builder()
                    .sampleId(sample.getId())
                    .sampleName(sample.getSampleName())
                    .enumTag(enumTagStr)
                    .modelResults(modelResults)
                    .build());
        }
        return AiModelAnalysisResultVO.builder().samples(samples).build();
    }

    @Override
    public AiModelDifferenceVO checkDifference(List<Long> modelIds) {
        Map<Long, Integer> sampleRefCount = new HashMap<>();
        for (Long modelId : modelIds) {
            for (Long sampleId : getModelSampleIds(modelId)) {
                sampleRefCount.merge(sampleId, 1, Integer::sum);
            }
        }

        List<Long> duplicatedIds = new ArrayList<>();
        List<Long> uniqueIds = new ArrayList<>();
        sampleRefCount.forEach((sampleId, count) -> {
            if (count >= 2) {
                duplicatedIds.add(sampleId);
            } else {
                uniqueIds.add(sampleId);
            }
        });

        return AiModelDifferenceVO.builder()
                .duplicatedSamples(buildSampleDetailVOList(duplicatedIds))
                .uniqueSamples(buildSampleDetailVOList(uniqueIds))
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long iterateModel(Long modelId, String newVersion, String description) {
        AiModelDO original = modelMapper.selectById(modelId);
        AiModelDO newModel = BeanUtils.toBean(original, AiModelDO.class);
        newModel.setId(null);
        newModel.setVersion(newVersion);
        newModel.setDescription(description);
        newModel.setStatus(2);
        modelMapper.insert(newModel);

        List<AiModelSampleRelateDO> newRelates = modelSampleRelateMapper.selectList(new LambdaQueryWrapper<AiModelSampleRelateDO>()
                        .eq(AiModelSampleRelateDO::getModelId, modelId))
                .stream()
                .map(relate -> AiModelSampleRelateDO.builder()
                        .modelId(newModel.getId())
                        .sampleId(relate.getSampleId())
                        .build())
                .toList();
        if (CollUtil.isNotEmpty(newRelates)) {
            modelSampleRelateMapper.insertBatch(newRelates);
        }
        return newModel.getId();
    }

    private AiModelAnalysisResultVO.ModelAnalysisResult buildModelAnalysis(AiSampleDO sample, List<AiSampleTagDO> enumTags,
                                                                           Long modelId) {
        AiModelDO model = modelMapper.selectById(modelId);
        if (model == null) {
            return null;
        }

        String speciesResult = null;
        BigDecimal speciesMatchRate = null;
        String emotionResult = null;
        BigDecimal emotionMatchRate = null;

        JSONObject translateResult = requestTranslate(sample, model);
        if (translateResult != null) {
            speciesResult = translateResult.getString("species_labels");
            AiSampleTagGroupDO speciesGroup = getGroupByName("物种识别");
            if (speciesGroup != null) {
                speciesMatchRate = calculateMatchRate(speciesResult, enumTags, speciesGroup.getId());
            }

            JSONObject intentResult = translateResult.getJSONObject("intent_result");
            JSONObject probabilities = intentResult == null ? null : intentResult.getJSONObject("probabilities");
            if (probabilities != null && !probabilities.isEmpty()) {
                String emotionKey = probabilities.entrySet().stream()
                        .max(Comparator.comparingDouble(entry -> ((Number) entry.getValue()).doubleValue()))
                        .map(Map.Entry::getKey)
                        .orElse(null);
                if (StrUtil.isNotBlank(emotionKey) && emotionKey.contains("_")) {
                    emotionResult = emotionKey.split("_")[1];
                    AiSampleTagGroupDO emotionGroup = getGroupByName("情绪识别");
                    if (emotionGroup != null) {
                        emotionMatchRate = calculateMatchRate(emotionResult, enumTags, emotionGroup.getId());
                    }
                }
            }
        }

        return AiModelAnalysisResultVO.ModelAnalysisResult.builder()
                .modelId(model.getId())
                .modelName(model.getModelName())
                .modelVersion(model.getVersion())
                .speciesResult(speciesResult)
                .speciesMatchRate(speciesMatchRate)
                .emotionResult(emotionResult)
                .emotionMatchRate(emotionMatchRate)
                .build();
    }

    private JSONObject requestTranslate(AiSampleDO sample, AiModelDO model) {
        try {
            String fileUrl = fileServer + sample.getSampleFilePath();
            String response = HttpRequest.post(translateServer)
                    .form("audio_data", HttpUtil.downloadBytes(fileUrl), sample.getSampleName())
                    .form("model_name", model.getModelName())
                    .form("model_version", model.getVersion())
                    .timeout(20000)
                    .execute().body();
            JSONObject result = JSON.parseObject(response);
            if (result == null || result.isEmpty() || !result.containsKey("intent_result")) {
                return null;
            }
            if (!Boolean.TRUE.equals(result.getBoolean("is_species_sound")) || result.getDoubleValue("confidence") < 0.7) {
                return null;
            }
            JSONObject intent = result.getJSONObject("intent_result");
            return intent != null && intent.getDoubleValue("confidence") >= 0.7 ? result : null;
        } catch (Exception ex) {
            log.error("调用翻译API失败，样本ID: {}", sample.getId(), ex);
            return null;
        }
    }

    private List<Long> getSampleModelIds(Long sampleId) {
        return modelSampleRelateMapper.selectList(new LambdaQueryWrapper<AiModelSampleRelateDO>()
                        .eq(AiModelSampleRelateDO::getSampleId, sampleId))
                .stream().map(AiModelSampleRelateDO::getModelId).toList();
    }

    private Set<Long> getModelSampleIds(Long modelId) {
        return modelSampleRelateMapper.selectList(new LambdaQueryWrapper<AiModelSampleRelateDO>()
                        .eq(AiModelSampleRelateDO::getModelId, modelId))
                .stream().map(AiModelSampleRelateDO::getSampleId).collect(Collectors.toSet());
    }

    private List<AiSampleDetailVO> buildSampleDetailVOList(List<Long> sampleIds) {
        return sampleIds.stream().map(this::buildSampleDetailVO).toList();
    }

    private AiSampleDetailVO buildSampleDetailVO(Long sampleId) {
        AiSampleDO sample = sampleMapper.selectById(sampleId);
        List<Long> tagIds = sampleTagRelateMapper.selectList(new LambdaQueryWrapper<AiSampleTagRelateDO>()
                        .eq(AiSampleTagRelateDO::getSampleId, sampleId))
                .stream().map(AiSampleTagRelateDO::getSampleTagId).toList();

        List<AiSampleDetailVO.TagInfo> enumTags = new ArrayList<>();
        List<AiSampleDetailVO.TagInfo> customTags = new ArrayList<>();
        for (AiSampleTagDO tag : sampleTagMapper.selectBatchIds(tagIds)) {
            AiSampleDetailVO.TagInfo tagInfo = AiSampleDetailVO.TagInfo.builder()
                    .id(tag.getId())
                    .tagName(tag.getTagName())
                    .enumValue(tag.getEnumValue())
                    .groupName(getTagGroupName(tag.getGroupId()))
                    .build();
            if (Integer.valueOf(1).equals(tag.getTagType())) {
                enumTags.add(tagInfo);
            } else {
                customTags.add(tagInfo);
            }
        }

        List<Long> modelIds = getSampleModelIds(sampleId);
        List<AiSampleDetailVO.ModelInfo> relatedModels = modelMapper.selectBatchIds(modelIds).stream()
                .map(model -> AiSampleDetailVO.ModelInfo.builder()
                        .id(model.getId())
                        .modelName(model.getModelName())
                        .version(model.getVersion())
                        .build())
                .toList();

        return AiSampleDetailVO.builder()
                .id(sample.getId())
                .sampleName(sample.getSampleName())
                .sampleFilePath(sample.getSampleFilePath())
                .enumTags(enumTags)
                .customTags(customTags)
                .relatedModels(relatedModels)
                .build();
    }

    private String getTagGroupName(String groupIds) {
        if (StrUtil.isBlank(groupIds)) {
            return "";
        }
        AiSampleTagGroupDO group = sampleTagGroupMapper.selectById(Long.parseLong(groupIds.split(StrUtil.COMMA)[0].trim()));
        return group == null ? "" : group.getGroupName();
    }

    private List<AiSampleTagDO> getEnumTagsForSample(Long sampleId) {
        List<Long> tagIds = sampleTagRelateMapper.selectList(new LambdaQueryWrapper<AiSampleTagRelateDO>()
                        .eq(AiSampleTagRelateDO::getSampleId, sampleId))
                .stream().map(AiSampleTagRelateDO::getSampleTagId).toList();
        return sampleTagMapper.selectBatchIds(tagIds).stream()
                .filter(tag -> Integer.valueOf(1).equals(tag.getTagType()))
                .toList();
    }

    private AiSampleTagGroupDO getGroupByName(String groupName) {
        return sampleTagGroupMapper.selectOne(new LambdaQueryWrapper<AiSampleTagGroupDO>()
                .eq(AiSampleTagGroupDO::getGroupName, groupName));
    }

    private BigDecimal calculateMatchRate(String recognitionValue, List<AiSampleTagDO> enumTags, Long groupId) {
        if (StrUtil.isBlank(recognitionValue) || CollUtil.isEmpty(enumTags)) {
            return BigDecimal.ZERO;
        }
        for (AiSampleTagDO tag : enumTags) {
            if (tag.getGroupId().contains(groupId.toString())) {
                if (recognitionValue.equalsIgnoreCase(tag.getTagName())
                        || recognitionValue.contains(tag.getTagName())
                        || tag.getTagName().contains(recognitionValue)) {
                    return BigDecimal.ONE;
                }
            }
        }
        return BigDecimal.ZERO;
    }
}

