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

import be.tarsos.dsp.AudioDispatcher;
import be.tarsos.dsp.AudioEvent;
import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
import be.tarsos.dsp.pitch.PitchDetectionHandler;
import be.tarsos.dsp.pitch.PitchDetectionResult;
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.dto.MusicPitchDetailDto;
import com.ym.mec.biz.dal.dto.SoundCheckHelper;
import com.ym.mec.biz.dal.dto.SoundCheckInfoDto;
import com.ym.mec.biz.dal.dto.WebSocketInfo;
import com.ym.mec.biz.dal.enums.WebsocketTypeEnum;
import com.ym.mec.biz.handler.WebSocketHandler;
import com.ym.mec.biz.service.SoundSocketService;
import com.ym.mec.biz.service.WebSocketEventHandler;
import com.ym.mec.common.exception.BizException;
import org.omg.PortableInterceptor.SYSTEM_EXCEPTION;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author Joburgess
 * @Date 2021/8/19 0019
 */
@Service
public class SoundCheckHandler implements WebSocketEventHandler {

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

    private final int SIZE = 44100;

    /** 校音数据 */
    private Map<String, SoundCheckHelper> userSoundCheckInfo = new ConcurrentHashMap<>();

    public SoundCheckHandler() {
        WebSocketHandler.regist(WebsocketTypeEnum.SOUND_CHECK, this);
    }

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

    }

    @Override
    public void receiveTextMessage(WebSocketSession session, String phone, WebSocketInfo message) {
        switch (message.getHeader().getCommond()) {
            case SoundSocketService.CHECK_END:
                userSoundCheckInfo.remove(phone);
                break;
            default:
                userSoundCheckInfo.put(phone, new SoundCheckHelper(442));
                JSONObject body = (JSONObject) message.getBody();
                if(body.containsKey("frequency")){
                    userSoundCheckInfo.get(phone).setFrequency(body.getDoubleValue("frequency"));
                }
                break;
        }
    }

    @Override
    public void receiveBinaryMessage(WebSocketSession session, String phone, BinaryMessage message) {
        if(!userSoundCheckInfo.containsKey(phone)){
            return;
        }
        try {
            AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), SoundCompareHandler.soundCompareConfig.audioFormat, SoundCompareHandler.soundCompareConfig.simpleSize, SoundCompareHandler.soundCompareConfig.overlap);
            dispatcher.addAudioProcessor(new PitchProcessor(SoundCompareHandler.soundCompareConfig.algo, SoundCompareHandler.soundCompareConfig.simpleRate, SoundCompareHandler.soundCompareConfig.simpleSize, (pitchDetectionResult, audioEvent) -> {
                if(!userSoundCheckInfo.containsKey(phone)){
                    return;
                }
                if(pitchDetectionResult.getPitch()<=0){
                    return;
                }
                double normalCents = PitchConverter.hertzToAbsoluteCent(userSoundCheckInfo.get(phone).getFrequency());
                double recordCents = PitchConverter.hertzToAbsoluteCent(pitchDetectionResult.getPitch());
                if(Math.abs(normalCents - recordCents)<3){
                    userSoundCheckInfo.get(phone).setRightSize(userSoundCheckInfo.get(phone).getRightSize() + audioEvent.getBufferSize());
                    userSoundCheckInfo.get(phone).getErrorNum().set(0);
                    WebSocketHandler.sendTextMessage(phone, WebSocketInfo.success("checking", "trend", 0));
                }else if(Math.abs(normalCents - recordCents)>=3){
                    userSoundCheckInfo.get(phone).getErrorNum().getAndIncrement();
                    WebSocketHandler.sendTextMessage(phone, WebSocketInfo.success("checking", "trend", normalCents>recordCents?-1:1));
                }
            }));
            dispatcher.run();
            if(userSoundCheckInfo.get(phone).getRightSize()>SIZE){
                WebSocketHandler.sendTextMessage(phone, WebSocketInfo.success("checkDone"));
                userSoundCheckInfo.remove(phone);
            }else if(userSoundCheckInfo.get(phone).getErrorNum().get()>5){
                userSoundCheckInfo.get(phone).setRightSize(0);
            }
        } catch (UnsupportedAudioFileException e) {
            throw new BizException("{}校音异常：{}", phone, e);
        }
    }

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

    }
}
