package com.cooleshow.musictuner.utils;

import android.util.Log;

import com.cooleshow.musictuner.bean.VoiceToneBean;

import java.util.ArrayList;

/**
 * Author by pq, Date on 2022/10/13.
 */
public class VoiceDataUtils {
    public static volatile VoiceDataUtils instance;
    public static final String[] VOICE_OF_TONE = new String[]{"C", "C♯", "D", "D♯", "E", "F", "F♯", "G", "G♯", "A", "A♯", "B"};
    public static final double[] ALL_VOICE_SAMPLES = new double[]{16.35, 17.32, 18.35, 19.45, 20.60, 21.83, 23.12, 24.50, 25.96, 27.50, 29.14, 30.87,
            32.70, 34.65, 36.71, 38.89, 41.20, 43.65, 46.25, 49.00, 51.91, 55.00, 58.27, 61.74,
            65.41, 69.30, 73.42, 77.78, 82.41, 87.31, 92.50, 98.00, 103.8, 110.0, 116.5, 123.5,
            130.8, 138.6, 146.8, 155.6, 164.8, 174.6, 185.0, 196.0, 207.7, 220.0, 233.1, 246.9,
            261.6, 277.2, 293.7, 311.1, 329.6, 349.2, 370.0, 392.0, 415.3, 440.0, 466.2, 493.9,
            523.3, 554.4, 587.3, 622.3, 659.3, 698.5, 740.0, 784.0, 830.6, 880.0, 932.3, 987.8,
            1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976,
            2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951,
            4186, 4435, 4699, 4978, 5274, 5588, 5920, 6272, 6645, 7040, 7459, 7902};
    public ArrayList<VoiceToneBean> voiceToneBeans;

    private VoiceDataUtils() {
        buildData();
    }

    public static VoiceDataUtils getInstance() {
        if (instance == null) {
            synchronized (VoiceDataUtils.class) {
                if (instance == null) {
                    instance = new VoiceDataUtils();
                }
            }
        }
        return instance;
    }

    public void buildData() {
        voiceToneBeans = new ArrayList<>();
        for (int i = 0; i < VOICE_OF_TONE.length; i++) {
            for (int j = 0; j < 9; j++) {
                VoiceToneBean voiceToneBean = new VoiceToneBean();
                voiceToneBean.name = VOICE_OF_TONE[i] + j;
                int position = i + j * 12;//0(0+0*12) 12(0+1*12) 24(0+2*12)
                voiceToneBean.voiceFrequencyValue = ALL_VOICE_SAMPLES[position];
                voiceToneBeans.add(voiceToneBean);
            }
        }
        Log.i("pq", "voiceToneBeans:" + voiceToneBeans.size());
        for (int i = 0; i < voiceToneBeans.size(); i++) {
            VoiceToneBean voiceToneBean = voiceToneBeans.get(i);
            Log.i("pq", "data name:" + voiceToneBean.name);
            Log.i("pq", "data voiceFrequencyValue:" + voiceToneBean.voiceFrequencyValue);
        }
    }

    public VoiceToneBean searchTarget(float targetVoiceFrequencyValue) {
        if (targetVoiceFrequencyValue == -1) {
            return null;
        }
        if (targetVoiceFrequencyValue > ALL_VOICE_SAMPLES[ALL_VOICE_SAMPLES.length - 1]) {
            VoiceToneBean voiceToneBean = buildBean(ALL_VOICE_SAMPLES.length - 2, ALL_VOICE_SAMPLES.length - 3, ALL_VOICE_SAMPLES.length - 1);
            voiceToneBean.difference = String.valueOf(targetVoiceFrequencyValue - ALL_VOICE_SAMPLES[ALL_VOICE_SAMPLES.length - 2]);
            return voiceToneBean;
        }
        if (targetVoiceFrequencyValue < ALL_VOICE_SAMPLES[0]) {
            VoiceToneBean voiceToneBean = buildBean(1, 0, 2);
            voiceToneBean.difference = String.valueOf(targetVoiceFrequencyValue - ALL_VOICE_SAMPLES[1]);
            return voiceToneBean;
        }
        int index = firstIndex(ALL_VOICE_SAMPLES, targetVoiceFrequencyValue);
        int start = index - 1;
        int end = index;
        int resultPosition = start;
        Log.i("qaz", "targetVoiceFrequencyValue:" + targetVoiceFrequencyValue);
        Log.i("qaz", "start:" + ALL_VOICE_SAMPLES[start]);
        Log.i("qaz", "end:" + ALL_VOICE_SAMPLES[end]);
        double startDiff = Math.abs(ALL_VOICE_SAMPLES[start] - targetVoiceFrequencyValue);
        double endDiff = Math.abs(ALL_VOICE_SAMPLES[end] - targetVoiceFrequencyValue);

        if (startDiff <= endDiff) {
            resultPosition = start;
        } else {
            resultPosition = end;
        }
        VoiceToneBean voiceToneBean = buildBean(resultPosition, resultPosition - 1, resultPosition + 1);
        voiceToneBean.difference = String.valueOf(targetVoiceFrequencyValue - ALL_VOICE_SAMPLES[resultPosition]);
        return voiceToneBean;
    }

    private VoiceToneBean buildBean(int pos, int beforePos, int afterPos) {
        VoiceToneBean voiceToneBean = new VoiceToneBean();
        voiceToneBean.name = countName(pos);
        voiceToneBean.voiceFrequencyValue = ALL_VOICE_SAMPLES[pos];
        voiceToneBean.beforeName = countName(beforePos);
        voiceToneBean.beforeVoiceFrequencyValue = ALL_VOICE_SAMPLES[beforePos];
        voiceToneBean.afterName = countName(afterPos);
        voiceToneBean.afterVoiceFrequencyValue = ALL_VOICE_SAMPLES[afterPos];
        Log.i("qaz", "result name:" + voiceToneBean.name +
                "\nvalue:" + voiceToneBean.voiceFrequencyValue);
        return voiceToneBean;
    }

    private String countName(int pos) {
        int row = pos / 12;
        int frequencyValuePosition = (pos % 12);
        String result = VOICE_OF_TONE[frequencyValuePosition] + row;
        return result;
    }

    private int firstIndex(double[] A, double target) {
        int start = 0, end = A.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (A[mid] < target) {
                start = mid;
            } else if (A[mid] > target) {
                end = mid;
            } else {
                end = mid;
            }
        }

        if (A[start] >= target) {
            return start;
        }
        if (A[end] >= target) {
            return end;
        }
        return A.length;
    }
}
