package com.ym.mec.biz.service.impl;

import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.pitch.PitchProcessor;
import be.tarsos.dsp.util.PitchConverter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ym.mec.biz.dal.config.SoundCompareConfig;
import com.ym.mec.biz.dal.dao.SysMusicScoreAccompanimentDao;
import com.ym.mec.biz.dal.dto.*;
import com.ym.mec.biz.dal.entity.SysMusicCompareRecord;
import com.ym.mec.biz.dal.enums.*;
import com.ym.mec.biz.handler.WebSocketHandler;
import com.ym.mec.biz.service.SoundSocketService;
import com.ym.mec.biz.service.SysMusicCompareRecordService;
import com.ym.mec.biz.service.WebSocketEventHandler;
import com.ym.mec.common.constant.CommonConstants;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.thirdparty.storage.StoragePluginContext;
import com.ym.mec.thirdparty.storage.provider.KS3StoragePlugin;
import com.ym.mec.util.upload.UploadUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static com.ym.mec.biz.service.SoundSocketService.VIDEO_UPDATE;

/**
 * @Author Joburgess
 * @Date 2021/8/5 0005
 */
@Service
public class SoundCompareHandler implements WebSocketEventHandler {

    private final Logger LOGGER = LoggerFactory.getLogger(SoundCompareHandler.class);

    private BigDecimal oneHundred = new BigDecimal(100);

    private final String tmpDir = "/mdata/soundCompare/";
    /**
     * @describe 用户对应评分信息
     */
    private Map<String, SoundCompareHelper> userSoundInfoMap = new ConcurrentHashMap<>();
    /**
     * @describe 音频处理参数
     */
    public static final SoundCompareConfig soundCompareConfig = new SoundCompareConfig();

    @Autowired
    private StoragePluginContext storagePluginContext;
    @Autowired
    private SysMusicCompareRecordService sysMusicCompareRecordService;
    @Autowired
    private SysMusicScoreAccompanimentDao sysMusicScoreAccompanimentDao;

    public SoundCompareHandler() {
        WebSocketHandler.regist(WebsocketTypeEnum.SOUND_COMPARE, this);
        File soundDir = new File(tmpDir);
        if(!soundDir.exists()){
            soundDir.mkdir();
        }
    }

    @Override
    public void afterConnectionEstablished(WebSocketSession session, String phone) {

    }

    @Override
    public void receiveTextMessage(WebSocketSession session, String phone, WebSocketInfo message) {
        JSONObject bodyObject = (JSONObject) message.getBody();

        switch (message.getHeader().getCommond()){
            case SoundSocketService.MUSIC_XML:
                if(userSoundInfoMap.containsKey(phone)){
                    createHeader(phone, false);
                }
                userSoundInfoMap.put(phone, new SoundCompareHelper());
                userSoundInfoMap.get(phone).setClientId(((OAuth2Authentication)session.getPrincipal()).getOAuth2Request().getClientId());
                List<MusicPitchDetailDto> musicXmlInfos = JSON.parseArray(bodyObject.getString("musicXmlInfos"), MusicPitchDetailDto.class);
                userSoundInfoMap.get(phone).setMusicXmlInfos(musicXmlInfos);
                musicXmlInfos = musicXmlInfos.stream().filter(m->!m.getDontEvaluating()).collect(Collectors.toList());
                userSoundInfoMap.get(phone).setMusicScoreId(bodyObject.getInteger("id"));
                if(bodyObject.containsKey("platform")){
                    userSoundInfoMap.get(phone).setDeviceType(DeviceTypeEnum.valueOf(bodyObject.getString("platform")));
                }
                if(bodyObject.containsKey("behaviorId")){
                    userSoundInfoMap.get(phone).setBehaviorId(bodyObject.getString("behaviorId"));
                }
                if(bodyObject.containsKey("detailId")){
                    userSoundInfoMap.get(phone).setDetailId(bodyObject.getInteger("detailId"));
                }
                if(bodyObject.containsKey("examSongId")){
                    userSoundInfoMap.get(phone).setExamSongId(bodyObject.getInteger("examSongId"));
                }
                if(bodyObject.containsKey("xmlUrl")){
                    userSoundInfoMap.get(phone).setXmlUrl(bodyObject.getString("xmlUrl"));
                }
                if(bodyObject.containsKey("heardLevel")){
                    userSoundInfoMap.get(phone).setHeardLevel(HeardLevelEnum.valueOf(bodyObject.getString("heardLevel")));
                }
                if(bodyObject.containsKey("speed")){
                    userSoundInfoMap.get(phone).setSpeed(bodyObject.getIntValue("speed"));
                }
                List<Integer> subjectIds = sysMusicScoreAccompanimentDao.findSubjectByMusicScoreId(userSoundInfoMap.get(phone).getMusicScoreId(), null);
                if(!CollectionUtils.isEmpty(subjectIds)){
                    userSoundInfoMap.get(phone).setSubjectId(subjectIds.get(0));
                }
                userSoundInfoMap.get(phone).setMeasureXmlInfoMap(musicXmlInfos.stream().collect(Collectors.groupingBy(MusicPitchDetailDto::getMeasureIndex)));
                musicXmlInfos.forEach(e->userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(e.getMusicalNotesIndex(), e.getFrequency()));
                for (Map.Entry<Integer, List<MusicPitchDetailDto>> userMeasureXmlInfoEntry : userSoundInfoMap.get(phone).getMeasureXmlInfoMap().entrySet()) {
                    MusicPitchDetailDto firstPitch = userMeasureXmlInfoEntry.getValue().stream().min(Comparator.comparing(MusicPitchDetailDto::getTimeStamp)).get();
                    MusicPitchDetailDto lastPitch = userMeasureXmlInfoEntry.getValue().stream().max(Comparator.comparing(MusicPitchDetailDto::getTimeStamp)).get();
                    long dc = userMeasureXmlInfoEntry.getValue().stream().filter(m -> m.getDontEvaluating()).count();
                    MusicPitchDetailDto musicPitchDetailDto = new MusicPitchDetailDto(firstPitch.getTimeStamp(), lastPitch.getTimeStamp() + lastPitch.getDuration());
                    musicPitchDetailDto.setDuration(musicPitchDetailDto.getEndTimeStamp()-musicPitchDetailDto.getTimeStamp());
                    musicPitchDetailDto.setDontEvaluating(dc == userMeasureXmlInfoEntry.getValue().size());
                    userSoundInfoMap.get(phone).getMeasureEndTime().put(userMeasureXmlInfoEntry.getKey(), musicPitchDetailDto);
                }
                SysMusicCompareRecord sysMusicCompareRecord = new SysMusicCompareRecord(FeatureType.CLOUD_STUDY_EVALUATION);
                sysMusicCompareRecordService.insert(sysMusicCompareRecord);
                LOGGER.info("评测记录编号：{}", sysMusicCompareRecord.getId());
                userSoundInfoMap.get(phone).setRecordId(sysMusicCompareRecord.getId());
                break;
            case SoundSocketService.RECORD_START:
                if(!userSoundInfoMap.containsKey(phone)){
                    break;
                }
                try {
                    File file = new File(tmpDir+phone + "_"+ userSoundInfoMap.get(phone).getMusicScoreId() +"_"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +".wav");
                    userSoundInfoMap.get(phone).setFile(file);
                    userSoundInfoMap.get(phone).setAccessFile(new RandomAccessFile(file, "rw"));
                    userSoundInfoMap.get(phone).setRecordFilePath(file.getAbsolutePath());
                } catch (FileNotFoundException e) {
                    throw new BizException("文件创建失败：", e);
                }
                break;
            case SoundSocketService.RECORD_END:
                if(!userSoundInfoMap.containsKey(phone)){
                    break;
                }
                try {
                    if(!CollectionUtils.isEmpty(userSoundInfoMap.get(phone).getMeasureEndTime())){
                        Integer lastMeasureIndex = userSoundInfoMap.get(phone).getMeasureEndTime().keySet().stream().min(Integer::compareTo).get();
                        double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(soundCompareConfig.audioFormat.getFrameSize()*soundCompareConfig.audioFormat.getFrameRate())*1000;
                        //如果结束时时长大于某小节，则此小节需要评分
                        if(recordTime>userSoundInfoMap.get(phone).getMeasureEndTime().get(lastMeasureIndex).getEndTimeStamp()){
                            measureCompare(phone, lastMeasureIndex);
                            userSoundInfoMap.get(phone).getMeasureEndTime().remove(lastMeasureIndex);
                        }
                    }
                } catch (IOException | NullPointerException e) {
                    LOGGER.error("评分错误：", e);
                } finally {
                    calTotalScore(phone);
                }
                createHeader(phone, true);
                break;
            case SoundSocketService.RECORD_CANCEL:
                createHeader(phone, false);
                break;
            case SoundSocketService.PROXY_MESSAGE:
                if(DeviceTypeEnum.IOS.equals(userSoundInfoMap.get(phone).getDeviceType())&&bodyObject.containsKey(SoundSocketService.OFFSET_TIME)){
                    int offsetTime = bodyObject.getIntValue(SoundSocketService.OFFSET_TIME);
                    calOffsetTime(phone, offsetTime);
                }
                break;
            case VIDEO_UPDATE:
                SysMusicCompareRecord update = null;
                if(bodyObject.containsKey("recordId")){
                    update = sysMusicCompareRecordService.get(bodyObject.getLong("recordId"));
                }
                if(Objects.nonNull(update)&&bodyObject.containsKey("filePath")){
                    update.setVideoFilePath(bodyObject.getString("filePath"));
                    sysMusicCompareRecordService.update(update);
                }else{
                    update.setVideoFilePath(update.getRecordFilePath());
                    sysMusicCompareRecordService.update(update);
                }
                WebSocketHandler.sendTextMessage(phone, message);
                break;
            default:
                break;
        }
    }

    @Override
    public void receiveBinaryMessage(WebSocketSession session, String phone, BinaryMessage message) {
        if(!userSoundInfoMap.containsKey(phone)){
            return;
        }
        try {
            if(Objects.nonNull(userSoundInfoMap.get(phone).getAccessFile())){
                userSoundInfoMap.get(phone).getAccessFile().write(message.getPayload().array());
            }

            AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), soundCompareConfig.audioFormat, soundCompareConfig.simpleSize, soundCompareConfig.overlap);

            dispatcher.addAudioProcessor(userSoundInfoMap.get(phone).silenceDetector);
            dispatcher.addAudioProcessor(new PitchProcessor(soundCompareConfig.algo, soundCompareConfig.simpleRate, soundCompareConfig.simpleSize, userSoundInfoMap.get(phone)));
            dispatcher.run();
            if(Objects.isNull(userSoundInfoMap.get(phone).getAccessFile())){
                return;
            }

            double recordTime = userSoundInfoMap.get(phone).getAccessFile().length()/(soundCompareConfig.audioFormat.getFrameSize()*soundCompareConfig.audioFormat.getFrameRate())*1000;
            userSoundInfoMap.get(phone).setMeasureStartTime(recordTime);
            for (Map.Entry<Integer, MusicPitchDetailDto> userMeasureEndTimeMapEntry : userSoundInfoMap.get(phone).getMeasureEndTime().entrySet()) {
                if(recordTime>(userMeasureEndTimeMapEntry.getValue().getEndTimeStamp())){
                    if(userMeasureEndTimeMapEntry.getValue().getDontEvaluating()){
                        continue;
                    }else{
                        measureCompare(phone, userMeasureEndTimeMapEntry.getKey());
                    }
                    userSoundInfoMap.get(phone).getMeasureEndTime().remove(userMeasureEndTimeMapEntry.getKey());
                    break;
                }
            }
        } catch (UnsupportedAudioFileException | IOException e) {
            throw new BizException("{}评分异常：{}", phone, e);
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, String phone){
        if(userSoundInfoMap.containsKey(phone)&&Objects.nonNull(userSoundInfoMap.get(phone).getFile())){
            createHeader(phone, false);
        }
        userSoundInfoMap.remove(phone);
    }

    /**
     * @describe 处理时间偏移
     * @author Joburgess
     * @date 2021/7/5 0005
     * @param phone:
     * @param offsetTime:
     * @return void
     */
    private void calOffsetTime(String phone, int offsetTime){
        userSoundInfoMap.get(phone).setOffsetTime(offsetTime);
        for (Map.Entry<Integer, MusicPitchDetailDto> musicPitchDetailDtoEntry : userSoundInfoMap.get(phone).getMeasureEndTime().entrySet()) {
            musicPitchDetailDtoEntry.getValue().setTimeStamp(musicPitchDetailDtoEntry.getValue().getTimeStamp() + offsetTime);
            musicPitchDetailDtoEntry.getValue().setEndTimeStamp(musicPitchDetailDtoEntry.getValue().getEndTimeStamp() + offsetTime);
        }
    }

    /**
     * @describe 保存录音数据，并生成wav头信息
     * @author Joburgess
     * @date 2021/6/25 0025
     * @param phone:
     * @return void
     */
    private void createHeader(String phone, boolean saveData){
        if(!userSoundInfoMap.containsKey(phone)){
            return;
        }
        if(Objects.nonNull(userSoundInfoMap.get(phone).getAccessFile())){
            try {
                RandomAccessFile randomAccessFile = userSoundInfoMap.get(phone).getAccessFile();
                LOGGER.info("音频时长：{}", randomAccessFile.length()/(soundCompareConfig.audioFormat.getFrameSize()*soundCompareConfig.audioFormat.getFrameRate())*1000);
                randomAccessFile.seek(0);
                randomAccessFile.write(WavHeader.getWaveHeader(randomAccessFile.length(), (long) soundCompareConfig.audioFormat.getFrameRate(), soundCompareConfig.audioFormat.getSampleSizeInBits()));
                randomAccessFile.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            userSoundInfoMap.get(phone).setAccessFile(null);
        }

        if(Objects.nonNull(userSoundInfoMap.get(phone).getFile())){
            String url = null;
            try {
                String folder = UploadUtil.getFileFloder();
                url = storagePluginContext.uploadFile(KS3StoragePlugin.PLUGIN_NAME,"cloud-coach/" + folder, userSoundInfoMap.get(phone).getFile());
            } catch (Exception e) {
                LOGGER.error("录音文件上传失败：{}", e);
            }
            userSoundInfoMap.get(phone).setRecordFilePath(url);
        }
        //存储评分数据
        if(saveData){
            sysMusicCompareRecordService.saveMusicCompareData(phone, userSoundInfoMap.get(phone));
            userSoundInfoMap.get(phone).setRecordId(null);
        }else if(Objects.nonNull(userSoundInfoMap.get(phone).getRecordId())){
            sysMusicCompareRecordService.delete(userSoundInfoMap.get(phone).getRecordId());
        }

        if(Objects.nonNull(userSoundInfoMap.get(phone).getFile())){
            userSoundInfoMap.get(phone).getFile().delete();
            userSoundInfoMap.get(phone).setFile(null);
            userSoundInfoMap.get(phone).setAccessFile(null);
        }
    }

    /**
     * @describe 数据比对，生成分数
     * @author Joburgess
     * @date 2021/6/25 0025
     * @param phone:
     * @param measureIndex:
     * @return void
     */
    private void measureCompare(String phone, int measureIndex){
        if (userSoundInfoMap.get(phone).getOffsetTime() == -1){
            userSoundInfoMap.get(phone).setOffsetTime(0);
        }

        //相似度
        BigDecimal intonation = BigDecimal.ZERO;
        //节奏
        BigDecimal cadence = BigDecimal.ZERO;
        //完整度
        BigDecimal integrity = BigDecimal.ZERO;

        try {
            //音准分数
            float intonationScore = 0;

            //节奏匹配数量
            float cadenceNum = 0;

            //完整性分数
            float integrityScore = 0;

            int totalCompareNum = userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).size();

            for (int i = 0; i < userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).size(); i++) {
                MusicPitchDetailDto musicXmlInfo = userSoundInfoMap.get(phone).getMeasureXmlInfoMap().get(measureIndex).get(i);

                int ot5 = (int) (musicXmlInfo.getDuration()*0.1);
                int startTimeStamp = musicXmlInfo.getTimeStamp() + userSoundInfoMap.get(phone).getOffsetTime() + ot5;
                int endTimeStamp = musicXmlInfo.getTimeStamp()  + userSoundInfoMap.get(phone).getOffsetTime() + musicXmlInfo.getDuration() - ot5;

                //时间范围内有效节奏数量
                float cadenceValidNum = 0;
                //时间范围内有效音频数量
                float integrityValidNum = 0;
                //时间范围内匹配次数
                float compareNum = 0;

                List<MusicPitchDetailDto> measureSoundPitchInfos = new ArrayList<>();

                for (int j = 0; j < userSoundInfoMap.get(phone).getRecordMeasurePithInfo().size(); j++) {
                    MusicPitchDetailDto recordInfo = userSoundInfoMap.get(phone).getRecordMeasurePithInfo().get(j);
                    //如果在时间范围之外直接跳过
                    if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
                        continue;
                    }
                    measureSoundPitchInfos.add(recordInfo);
                    compareNum++;
                    //如果在最低有效频率以下则跳过
                    if(recordInfo.getFrequency()<soundCompareConfig.validFrequency&&musicXmlInfo.getFrequency()!=-1){
                        continue;
                    }
                    cadenceValidNum++;
                    //如果频率差值在节奏误差范围内
//                    if(Math.abs(recordInfo.getFrequency()-musicXmlInfo.getFrequency())<=soundCompareConfig.integrityFrequencyRange){
//                        integrityValidNum++;
//                    }
                }

                //非正常频率次数
                int errPitchNum = 0;
                //分贝变化次数
                int decibelChangeNum = 0;

                if(CollectionUtils.isEmpty(measureSoundPitchInfos)){
                    userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(musicXmlInfo.getMusicalNotesIndex(), (float) 0);
                }else{
                    Map<Integer, Long> collect = measureSoundPitchInfos.stream().map(pitch -> (int)pitch.getFrequency()).collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()));
                    //出现次数最多的频率
                    Integer pitch = collect.entrySet().stream().max(Comparator.comparing(e -> e.getValue())).get().getKey();
                    //当前频率
                    double cf = -1;
                    //频率持续数量
                    int fnum = 0;
                    //是否演奏中
                    boolean ing = false;
                    //当前分贝
                    double cd = 0;
                    //分贝变化方向，-1变小，1变大
                    int dcd = -1;
                    //分贝持续数量
                    int dnum = 0;
                    for (MusicPitchDetailDto musicalNotesPitch : measureSoundPitchInfos) {
                        //计算频率断层次数
                        if (Math.abs(musicalNotesPitch.getFrequency() - cf) > 20){
                            fnum ++;
                        }
                        if (fnum>=5){
                            cf = musicalNotesPitch.getFrequency();
                            fnum = 0;
                            if (cf != -1){
                                errPitchNum ++;
                                ing = true;
                                cd = musicalNotesPitch.getDecibel();
                            }
                        }
                        //计算声音大小断层册数
                        if(ing && Math.abs(musicalNotesPitch.getDecibel() - cd) > 10){
                            dnum ++;
                        }
                        if (dnum > 2){
                            int tdcd = cd > musicalNotesPitch.getDecibel() ? -1 : 1;
                            cd = musicalNotesPitch.getDecibel();
                            dnum = 0;
                            if (tdcd != dcd) {
                                decibelChangeNum++;
                            }
                            dcd = tdcd;
                        }
                    }
                    userSoundInfoMap.get(phone).getMusicalNotePitchMap().put(musicXmlInfo.getMusicalNotesIndex(), (float) pitch);
                }

                boolean cadenceRight = false;
                boolean intonationRight = false;
                boolean integrityRight = false;

                //有效节奏占比
                float cadenceDuty = cadenceValidNum/compareNum;
                //如果频率出现断层或这个音量出现断层，则当前音符节奏无效
                if(errPitchNum>=2 || decibelChangeNum>1){
                    cadenceDuty = 0;
                }
                //节奏
                if(cadenceDuty>=userSoundInfoMap.get(phone).getHeardLevel().getCadenceRange()){
                    cadenceNum++;
                    cadenceRight = true;
                }
                //音准、完成度
                if (cadenceRight && !CollectionUtils.isEmpty(measureSoundPitchInfos)){
                    //音准
                    Double avgPitch = measureSoundPitchInfos.stream().filter(pitch -> Math.abs((pitch.getFrequency()-musicXmlInfo.getFrequency()))<15).collect(Collectors.averagingDouble(pitch -> pitch.getFrequency()));
                    //音分
                    double recordCents = 0;
                    if (avgPitch > 0){
                        recordCents = PitchConverter.hertzToAbsoluteCent(avgPitch);
                    }
                    double cents = 0;
                    if(musicXmlInfo.getFrequency()>0){
                        cents =  PitchConverter.hertzToAbsoluteCent(musicXmlInfo.getFrequency());
                    }
                    double score = 100 - Math.round(Math.abs(cents - recordCents)) + userSoundInfoMap.get(phone).getHeardLevel().getIntonationCentsRange();
                    if (score < 0){
                        score = 0;
                    }else if(score > 100){
                        score = 100;
                    }
                    intonationScore += score;
                    musicXmlInfo.setAvgFrequency(avgPitch.floatValue());
                    intonationRight = score>70;

                    if(score>0){
                        integrityValidNum = measureSoundPitchInfos.stream().filter(pitch -> Math.abs((pitch.getFrequency()-musicXmlInfo.getFrequency()))<15).count();
                    }else{
                        integrityValidNum = 0;
                    }
                }
                //完成度
                if(integrityValidNum > compareNum){
                    integrityValidNum = compareNum;
                }
                float integrityDuty = integrityValidNum/compareNum;
                integrityScore += integrityDuty;
                integrityRight = integrityDuty>0.7;

                if(!cadenceRight){
                    userSoundInfoMap.get(phone).getMusicalNotesPlayStats().add(new MusicalNotesPlayStatDto(musicXmlInfo.getMusicalNotesIndex(), MusicalErrorTypeEnum.CADENCE_WRONG));
                }else if(!intonationRight){
                    userSoundInfoMap.get(phone).getMusicalNotesPlayStats().add(new MusicalNotesPlayStatDto(musicXmlInfo.getMusicalNotesIndex(), MusicalErrorTypeEnum.INTONATION_WRONG));
                }else if(!integrityRight){
                    userSoundInfoMap.get(phone).getMusicalNotesPlayStats().add(new MusicalNotesPlayStatDto(musicXmlInfo.getMusicalNotesIndex(), MusicalErrorTypeEnum.INTEGRITY_WRONG));
                }else{
                    userSoundInfoMap.get(phone).getMusicalNotesPlayStats().add(new MusicalNotesPlayStatDto(musicXmlInfo.getMusicalNotesIndex(), MusicalErrorTypeEnum.RIGHT));
                }
            }

            BigDecimal measureNum = new BigDecimal(totalCompareNum);

            intonation = new BigDecimal(intonationScore).divide(measureNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(0, BigDecimal.ROUND_UP);
            cadence = new BigDecimal(cadenceNum).divide(measureNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_UP);
            integrity = new BigDecimal(integrityScore).divide(measureNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_UP);

        } catch (ArithmeticException e){
            LOGGER.info("无musicXml信息");
        }

        if(userSoundInfoMap.get(phone).getUserScoreMap().containsKey("intonation")){
            userSoundInfoMap.get(phone).getUserScoreMap().put("intonation", intonation.add(userSoundInfoMap.get(phone).getUserScoreMap().get("intonation")));
        }else{
            userSoundInfoMap.get(phone).getUserScoreMap().put("intonation", intonation);
        }

        if(userSoundInfoMap.get(phone).getUserScoreMap().containsKey("cadence")){
            userSoundInfoMap.get(phone).getUserScoreMap().put("cadence", cadence.add(userSoundInfoMap.get(phone).getUserScoreMap().get("cadence")));
        }else{
            userSoundInfoMap.get(phone).getUserScoreMap().put("cadence", cadence);
        }

        if(userSoundInfoMap.get(phone).getUserScoreMap().containsKey("integrity")){
            userSoundInfoMap.get(phone).getUserScoreMap().put("integrity", integrity.add(userSoundInfoMap.get(phone).getUserScoreMap().get("integrity")));
        }else{
            userSoundInfoMap.get(phone).getUserScoreMap().put("integrity", integrity);
        }

        //计算分数并推送
        createPushInfo(phone, "measureScore", measureIndex, intonation, cadence, integrity);
    }

    /**
     * @describe 计算最终评分
     * @author Joburgess
     * @date 2021/6/25 0025
     * @param phone:
     * @return void
     */
    private void calTotalScore(String phone) {
        int totalCompareNum = userSoundInfoMap.get(phone).getMeasureXmlInfoMap().keySet().size();
        int currentCompareNum = totalCompareNum-userSoundInfoMap.get(phone).getMeasureEndTime().keySet().size();
        BigDecimal intonation = BigDecimal.ZERO;
        BigDecimal cadence = BigDecimal.ZERO;
        BigDecimal integrity = BigDecimal.ZERO;

        if(currentCompareNum>0){
            intonation = userSoundInfoMap.get(phone).getUserScoreMap().get("intonation").divide(new BigDecimal(currentCompareNum), 0, BigDecimal.ROUND_DOWN);
            cadence = userSoundInfoMap.get(phone).getUserScoreMap().get("cadence").divide(new BigDecimal(currentCompareNum), 0, BigDecimal.ROUND_DOWN);
            integrity = userSoundInfoMap.get(phone).getUserScoreMap().get("integrity").divide(new BigDecimal(currentCompareNum), 0, BigDecimal.ROUND_DOWN);
        }

        //计算分数并推送
        createPushInfo(phone, "overall", -1, intonation, cadence, integrity);

        LOGGER.info("评分数据：{}", JSON.toJSONString(userSoundInfoMap.get(phone)));
    }

    /**
     * @describe 生成评分结果
     * @author Joburgess
     * @date 2021/6/25 0025
     * @param command:
     * @param measureIndex:
     * @param intonation:
     * @param cadence:
     * @param integrity:
     * @return com.ym.mec.biz.dal.dto.WebSocketInfo
     */
    private WebSocketInfo createPushInfo(String phone, String command, Integer measureIndex,
                                         BigDecimal intonation, BigDecimal cadence, BigDecimal integrity){
        WebSocketInfo webSocketInfo = new WebSocketInfo();
        webSocketInfo.setHeader(new WebSocketInfo.Head(command));
        Map<String, Object> result = new HashMap<>(5);
        //打击乐只看节奏分
        BigDecimal score = cadence;
        //非打击乐总分为平均分
        if(Objects.isNull(userSoundInfoMap.get(phone).getSubjectId())||userSoundInfoMap.get(phone).getSubjectId()!=23){
            score = intonation.add(cadence).add(integrity).divide(new BigDecimal(3), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(0, BigDecimal.ROUND_UP);
        }
        result.put("score", score);
        result.put("intonation", intonation);
        result.put("cadence", cadence);
        result.put("integrity", integrity);
        result.put("measureIndex", measureIndex);
        result.put("recordId", userSoundInfoMap.get(phone).getRecordId());
        webSocketInfo.setBody(result);

        userSoundInfoMap.get(phone).getUserMeasureScoreMap().put(measureIndex, result);

        LOGGER.info("{}小节评分：{}", phone, JSON.toJSONString(webSocketInfo));

        //推送结果
        WebSocketHandler.sendTextMessage(phone, webSocketInfo);
        return webSocketInfo;
    }
}
