package com.ym.mec.biz.dal.dto;

import be.tarsos.dsp.AudioEvent;
import be.tarsos.dsp.SilenceDetector;
import be.tarsos.dsp.pitch.PitchDetectionHandler;
import be.tarsos.dsp.pitch.PitchDetectionResult;
import com.ym.mec.biz.dal.enums.DeviceTypeEnum;
import com.ym.mec.biz.dal.enums.HeardLevelEnum;
import com.ym.mec.biz.service.impl.SoundCompareHandler;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author Joburgess
 * @Date 2021/6/22 0022
 */
public class SoundCompareHelper implements PitchDetectionHandler {

    @ApiModelProperty(value = "设备类型")
    private DeviceTypeEnum deviceType;

    @ApiModelProperty(value = "操作编号")
    private String behaviorId;

    @ApiModelProperty(value = "伴奏编号")
    private Integer musicScoreId;

    @ApiModelProperty(value = "声部编号")
    private Integer subjectId;

    @ApiModelProperty(value = "评测记录编号")
    private Long recordId;

    @ApiModelProperty(value = "评测等级")
    private HeardLevelEnum heardLevel = HeardLevelEnum.ADVANCED;

    @ApiModelProperty(value = "小节开始时间")
    private double measureStartTime = 0;

    @ApiModelProperty
    private RandomAccessFile accessFile;

    private File file;

    @ApiModelProperty(value = "录音文件地址")
    private String recordFilePath;

    @ApiModelProperty(value = "播放速度")
    private int speed = 90;

    @ApiModelProperty(value = "小节xml信息字典")
    private Map<Integer, List<MusicPitchDetailDto>> measureXmlInfoMap = new HashMap<>();

    @ApiModelProperty(value = "小节结束时间字典")
    private Map<Integer, MusicPitchDetailDto> measureEndTime = new HashMap<>();

    @ApiModelProperty(value = "录音音频信息")
    private List<MusicPitchDetailDto> recordMeasurePithInfo = new ArrayList<>();

    @ApiModelProperty(value = "小节分数记录")
    private Map<String, BigDecimal> userScoreMap = new HashMap<>();

    private Map<Integer, Map<String, Object>> userMeasureScoreMap = new HashMap<>();

    @ApiModelProperty(value = "音符频率字典")
    private Map<Integer, Float> musicalNotePitchMap = new HashMap<>();

    @ApiModelProperty(value = "每个音符评测结果")
    private List<MusicalNotesPlayStatDto> musicalNotesPlayStats = new ArrayList<>();

    @ApiModelProperty(value = "偏移时间量，解决客户端录音播放不同步导致的声音留白")
    private int offsetTime = -1;

    private List<MusicPitchDetailDto> musicXmlInfos;

    private String clientId;

    private Integer detailId;

    private Integer examSongId;

    private String xmlUrl;

    /**
     * @describe 分贝检测器
     */
    public SilenceDetector silenceDetector = new SilenceDetector();

    public List<MusicPitchDetailDto> getMusicXmlInfos() {
        return musicXmlInfos;
    }

    public void setMusicXmlInfos(List<MusicPitchDetailDto> musicXmlInfos) {
        this.musicXmlInfos = musicXmlInfos;
    }

    public Map<Integer, Float> getMusicalNotePitchMap() {
        return musicalNotePitchMap;
    }

    public void setMusicalNotePitchMap(Map<Integer, Float> musicalNotePitchMap) {
        this.musicalNotePitchMap = musicalNotePitchMap;
    }

    public Long getRecordId() {
        return recordId;
    }

    public void setRecordId(Long recordId) {
        this.recordId = recordId;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public String getBehaviorId() {
        return behaviorId;
    }

    public void setBehaviorId(String behaviorId) {
        this.behaviorId = behaviorId;
    }

    public Integer getSubjectId() {
        return subjectId;
    }

    public void setSubjectId(Integer subjectId) {
        this.subjectId = subjectId;
    }

    public HeardLevelEnum getHeardLevel() {
        return heardLevel;
    }

    public void setHeardLevel(HeardLevelEnum heardLevel) {
        this.heardLevel = heardLevel;
    }

    public DeviceTypeEnum getDeviceType() {
        return deviceType;
    }

    public void setDeviceType(DeviceTypeEnum deviceType) {
        this.deviceType = deviceType;
    }

    public Integer getDetailId() {
        return detailId;
    }

    public void setDetailId(Integer detailId) {
        this.detailId = detailId;
    }

    public Integer getExamSongId() {
        return examSongId;
    }

    public void setExamSongId(Integer examSongId) {
        this.examSongId = examSongId;
    }

    public String getXmlUrl() {
        return xmlUrl;
    }

    public void setXmlUrl(String xmlUrl) {
        this.xmlUrl = xmlUrl;
    }

    public int getOffsetTime() {
        return offsetTime;
    }

    public void setOffsetTime(int offsetTime) {
        this.offsetTime = offsetTime;
    }

    public Integer getMusicScoreId() {
        return musicScoreId;
    }

    public void setMusicScoreId(Integer musicScoreId) {
        this.musicScoreId = musicScoreId;
    }

    public RandomAccessFile getAccessFile() {
        return accessFile;
    }

    public File getFile() {
        return file;
    }

    public void setFile(File file) {
        this.file = file;
    }

    public String getRecordFilePath() {
        return recordFilePath;
    }

    public void setRecordFilePath(String recordFilePath) {
        this.recordFilePath = recordFilePath;
    }

    public void setAccessFile(RandomAccessFile accessFile) {
        this.accessFile = accessFile;
    }

    public String getClientId() {
        return clientId;
    }

    public void setClientId(String clientId) {
        this.clientId = clientId;
    }

    public double getMeasureStartTime() {
        return measureStartTime;
    }

    public void setMeasureStartTime(double measureStartTime) {
        this.measureStartTime = measureStartTime;
    }

    public Map<Integer, List<MusicPitchDetailDto>> getMeasureXmlInfoMap() {
        return measureXmlInfoMap;
    }

    public void setMeasureXmlInfoMap(Map<Integer, List<MusicPitchDetailDto>> measureXmlInfoMap) {
        this.measureXmlInfoMap = measureXmlInfoMap;
    }

    public Map<Integer, MusicPitchDetailDto> getMeasureEndTime() {
        return measureEndTime;
    }

    public void setMeasureEndTime(Map<Integer, MusicPitchDetailDto> measureEndTime) {
        this.measureEndTime = measureEndTime;
    }

    public List<MusicalNotesPlayStatDto> getMusicalNotesPlayStats() {
        return musicalNotesPlayStats;
    }

    public void setMusicalNotesPlayStats(List<MusicalNotesPlayStatDto> musicalNotesPlayStats) {
        this.musicalNotesPlayStats = musicalNotesPlayStats;
    }

    public List<MusicPitchDetailDto> getRecordMeasurePithInfo() {
        return recordMeasurePithInfo;
    }

    public void setRecordMeasurePithInfo(List<MusicPitchDetailDto> recordMeasurePithInfo) {
        this.recordMeasurePithInfo = recordMeasurePithInfo;
    }

    public Map<String, BigDecimal> getUserScoreMap() {
        return userScoreMap;
    }

    public void setUserScoreMap(Map<String, BigDecimal> userScoreMap) {
        this.userScoreMap = userScoreMap;
    }

    public Map<Integer, Map<String, Object>> getUserMeasureScoreMap() {
        return userMeasureScoreMap;
    }

    public void setUserMeasureScoreMap(Map<Integer, Map<String, Object>> userMeasureScoreMap) {
        this.userMeasureScoreMap = userMeasureScoreMap;
    }

    @Override
    public void handlePitch(PitchDetectionResult pitchDetectionResult, AudioEvent audioEvent) {
        int timeStamp = (int) (measureStartTime + audioEvent.getTimeStamp()*1000);
        float pitch = pitchDetectionResult.getPitch();
        if(offsetTime == -1 && !DeviceTypeEnum.IOS.equals(deviceType) && pitch>0){
            int preTimeStamp = CollectionUtils.isEmpty(recordMeasurePithInfo)?0:recordMeasurePithInfo.get(recordMeasurePithInfo.size()-1).getTimeStamp();
            offsetTime = timeStamp - (timeStamp - preTimeStamp)/2;
            for (MusicPitchDetailDto musicXmlInfo : musicXmlInfos) {
                if(!musicXmlInfo.getDontEvaluating()){
                    if(offsetTime > musicXmlInfo.getTimeStamp())
                        offsetTime = offsetTime - musicXmlInfo.getTimeStamp();
                    break;
                }
            }
            for (Map.Entry<Integer, MusicPitchDetailDto> musicPitchDetailDtoEntry : measureEndTime.entrySet()) {
                musicPitchDetailDtoEntry.getValue().setTimeStamp(musicPitchDetailDtoEntry.getValue().getTimeStamp() + offsetTime);
                musicPitchDetailDtoEntry.getValue().setEndTimeStamp(musicPitchDetailDtoEntry.getValue().getEndTimeStamp() + offsetTime);
            }
        }
        if(silenceDetector.currentSPL()< SoundCompareHandler.soundCompareConfig.validDb){
            pitch = -1;
        }
//            LOGGER.info("时间：{}, 频率：{}, 分贝：{}", timeStamp, pitch, silenceDetecor.currentSPL());
        recordMeasurePithInfo.add(new MusicPitchDetailDto(timeStamp, pitch, silenceDetector.currentSPL()));
    }
}
