package cn.api.media.utils;

import cn.api.media.rpc.ApiUtils;
import cn.api.media.rpc.Wav;
import cn.util.core.LogKit;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;

/**
 * WAV 文件头处理
 */
public class WaveHeader {

    public static final int AUDIO_TYPE_PCM_RAW = 0;
    public static final int AUDIO_TYPE_PCM_WAVE = 1;

    public static final int AUDIO_SAMPLE_RATE = 16000;
    public static final int AUDIO_BITS_PER_SAMPLE = 16;
    public static final int AUDIO_CHANNELS = 1;

    private static final int WAVE_HEADER_SIZE = 44;

    /**
     * 是否包含文件头
     *
     * @param audioData
     * @return
     */
    private boolean containsWaveHeader(byte[] audioData) {
        return (audioData.length > WAVE_HEADER_SIZE
                && audioData[0] == 'R'
                && audioData[1] == 'I'
                && audioData[2] == 'F'
                && audioData[3] == 'F'
                && audioData[8] == 'W'
                && audioData[9] == 'A'
                && audioData[10] == 'V'
                && audioData[11] == 'E');
    }

    /**
     * 去除wav文件头 得到pcm
     *
     * @param soureData
     * @param cleanSourceData
     * @return
     */
    private byte[] getWithoutWaveHeader(
            byte[] soureData,
            boolean cleanSourceData
    ) {
        int newSize = soureData.length - WAVE_HEADER_SIZE;
        byte[] newData = new byte[newSize];
        System.arraycopy(soureData, WAVE_HEADER_SIZE, newData, 0, newSize);

        if (cleanSourceData) {
            Arrays.fill(soureData, (byte) 0);
        }

        return newData;
    }

    /**
     * pcm 添加wav 文件头 得到wav 文件
     *
     * @param soureData
     * @param cleanSourceData
     * @return
     */
    private byte[] getWithWaveHeader(
            byte[] soureData,
            boolean cleanSourceData
    ) {

        int audioDataSize = soureData.length;
        int totalLength = soureData.length;
        int byteRate = AUDIO_BITS_PER_SAMPLE * AUDIO_SAMPLE_RATE * 1 / 8;

        byte[] newData = new byte[audioDataSize + WAVE_HEADER_SIZE];

        newData[0] = 'R'; // RIFF/WAVE header
        newData[1] = 'I';
        newData[2] = 'F';
        newData[3] = 'F';
        newData[4] = (byte) (audioDataSize & 0xff);
        newData[5] = (byte) ((audioDataSize >> 8) & 0xff);
        newData[6] = (byte) ((audioDataSize >> 16) & 0xff);
        newData[7] = (byte) ((audioDataSize >> 24) & 0xff);
        newData[8] = 'W';
        newData[9] = 'A';
        newData[10] = 'V';
        newData[11] = 'E';
        newData[12] = 'f'; // 'fmt ' chunk
        newData[13] = 'm';
        newData[14] = 't';
        newData[15] = ' ';
        newData[16] = 16; // 4 bytes: size of 'fmt ' chunk
        newData[17] = 0;
        newData[18] = 0;
        newData[19] = 0;
        newData[20] = 1; // format = 1
        newData[21] = 0;
        newData[22] = (byte) AUDIO_CHANNELS;
        newData[23] = 0;
        newData[24] = (byte) (AUDIO_SAMPLE_RATE & 0xff);
        newData[25] = (byte) ((AUDIO_SAMPLE_RATE >> 8) & 0xff);
        newData[26] = (byte) ((AUDIO_SAMPLE_RATE >> 16) & 0xff);
        newData[27] = (byte) ((AUDIO_SAMPLE_RATE >> 24) & 0xff);
        newData[28] = (byte) (byteRate & 0xff);
        newData[29] = (byte) ((byteRate >> 8) & 0xff);
        newData[30] = (byte) ((byteRate >> 16) & 0xff);
        newData[31] = (byte) ((byteRate >> 24) & 0xff);
        newData[32] = (byte) 2; // block align
        newData[33] = 0;
        newData[34] = AUDIO_BITS_PER_SAMPLE;
        newData[35] = 0;
        newData[36] = 'd';
        newData[37] = 'a';
        newData[38] = 't';
        newData[39] = 'a';
        newData[40] = (byte) (totalLength & 0xff);
        newData[41] = (byte) ((totalLength >> 8) & 0xff);
        newData[42] = (byte) ((totalLength >> 16) & 0xff);
        newData[43] = (byte) ((totalLength >> 24) & 0xff);

        System.arraycopy(soureData, 0, newData, WAVE_HEADER_SIZE, audioDataSize);

        if (cleanSourceData) {
            Arrays.fill(soureData, (byte) 0);
        }

        return newData;

    }


    /**
     * 音频 格式
     *
     * @return 格式
     */
    private AudioFormat getAudioFormat() {
        // 48000 16000
        float sampleRate = 16000;
        // 8000,11025,16000,22050,44100
        int sampleSizeInBits = 16;
        // 8,16
        int channels = 1;
        // 1,2
        boolean signed = true;
        // true,false
        boolean bigEndian = false;
        // true,false
        return new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);
    }// end getAudioFormat

    /**
     * Java api 保存音频
     */
    private void setAudioTypePcmWave() {

        ByteArrayInputStream bais;
        AudioInputStream ais;
        File audioFile = new File("D:\\test2.wav");

        try {
            AudioFormat audioFormat = getAudioFormat();
            byte audioData[] = new byte[1024];
            bais = new ByteArrayInputStream(audioData);
            ais = new AudioInputStream(bais, audioFormat, audioData.length / audioFormat.getFrameSize());
            //定义最终保存的文件名
            AudioSystem.write(ais, AudioFileFormat.Type.WAVE, audioFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 保存 并 发起 实时 转写
     */
    private void httpRequest() {

        String target = "D:\\test.wav";
        try {
            Converter.parseFile("D:\\test.pcm", target);
            File audioFile = new File(target);

            if (audioFile.canRead()) {

                FileInputStream fileInputStream = new FileInputStream(audioFile);
                byte[] byt = new byte[fileInputStream.available()];
                fileInputStream.read(byt);

                Wav waveFile = new Wav();
                waveFile.GetFromBytes(byt);
                String result = ApiUtils.sendToServer("qwertasd", waveFile.fs, waveFile.samples);
            }
        } catch (Exception e) {
            LogKit.info(e.getMessage());
        }
    }
}
