import os.path
import warnings
import wave
import pickle
from collections import deque
from UniTAP.common.audio_mode import AudioMode, AudioFileFormat
from UniTAP.libs.lib_tsi.tsi import sizeof, c_uint32


def save_to_wave_file(path: str, audio_mode: AudioMode, data: bytearray):
    if len(data) <= 0:
        raise ValueError(f"Audio data must not be empty! Current size {len(data)}")

    file = wave.Wave_write(path + ".wav")
    file.setframerate(audio_mode.sample_rate)
    file.setnchannels(audio_mode.channel_count)
    file.setsampwidth(int(audio_mode.bits / 8))
    file.writeframesraw(data)
    file.close()


def save_to_bin_file(path: str, data: bytearray):
    if len(data) <= 0:
        raise ValueError(f"Audio data must not be empty! Current size {len(data)}")

    bin_file = open(path + '.bin', 'wb')
    bin_file.write(data)
    bin_file.close()


def load_from_bin_file(path: str):
    file = open(path, "rb")
    data = pickle.load(file)
    file.close()

    return data, AudioMode(), len(data)


def load_from_wave_file(path: str):
    try:
        data = wave.open(path, 'rb')
    except wave.Error:
        raise NotImplementedError("Python Wave package doesn't support not PCM formats. Please, use PCM format WAV "
                                  "file.")

    channels = 2 if data.getnchannels() <= 2 else 8
    size = data.getnframes() * channels * sizeof(c_uint32) + sizeof(c_uint32)
    channel_count = data.getnchannels()
    sample_rate = data.getframerate()
    bits = data.getsampwidth() * 8
    bytes_block = data.readframes(size)
    data.close()
    ret_list = [0] * size

    list_of_data = deque(list(bytes_block))
    for i in range(0, len(ret_list), (channels * sizeof(c_uint32))):
        for j in range(data.getsampwidth() * channel_count):
            if len(list_of_data) == 0:
                break
            idx = i // (channels * sizeof(c_uint32)) * channels * sizeof(c_uint32) + j
            chunk_num = j // data.getsampwidth()
            addition = chunk_num * data.getsampwidth()
            if data.getsampwidth() == 2:
                ret_list[idx + addition + 1] = list_of_data.popleft()
            else:
                ret_list[idx + addition] = list_of_data.popleft()

    audio_mode = AudioMode()
    audio_mode.channel_count = channel_count
    audio_mode.sample_rate = sample_rate
    audio_mode.bits = bits

    return bytes(ret_list), audio_mode, len(ret_list)


def check_file_format(path: str):
    if not os.path.exists(path):
        return AudioFileFormat.UNKNOWN

    filename, file_extension = os.path.splitext(path)
    if file_extension.lower() == 'bin':
        return AudioFileFormat.BIN
    elif file_extension.lower() not in ["wav", "wave"]:
        return AudioFileFormat.WAV
    else:
        return AudioFileFormat.UNKNOWN


def create_audio_sts(audio_mode: AudioMode):
    sts_b = [0] * 48

    sts_b[0] = 0
    sts_b[0] |= 4
    sts_b[24] = sts_b[0]
    rate = audio_mode.sample_rate
    bits = audio_mode.bits

    dict_sample_rate = {22050: 4, 44100: 0, 88200: 8, 176400: 12, 24000: 6, 48000: 2, 96000: 10, 192000: 14,
                        32000: 3,
                        768000: 9}
    dict_bits = {16: 2, 20: 10, 24: 11}
    smpl = dict_sample_rate.get(rate)
    sts_b[3] = smpl
    sts_b[27] = sts_b[3]
    smlen = dict_bits.get(bits)
    sts_b[4] = smlen
    sts_b[28] = sts_b[4]

    return sts_b
