import pyaudio
import wave

pa = pyaudio.PyAudio()

def get_microphone():
    """
    creates cli prompt that lists all microphones available, and waits for user choices, and returns values that is needed to open microphone from pyaudio.
    uses dict as return type for ... I am very dumb and can not remember every line of the code.
    :return: {
        "device_num": device_num,
        "microphone_channel_num": microphone_channel_num,
        "microphone_sample_rate": microphone_sample_rate,
    }
    """

    def get_valid_integer(prompt, min_value, max_value):
        """
        Prompt the user for an integer input within a specified range.
        Sanitizes non-integer input and values outside the range.

        :param prompt: The input prompt message
        :param min_value: Minimum acceptable integer value (inclusive)
        :param max_value: Maximum acceptable integer value (inclusive)
        :return: A valid integer within the range [min_value, max_value]
        """
        while True:
            try:
                user_input = input(prompt)

                value = int(user_input)

                if min_value <= value <= max_value:
                    return value
                else:
                    print(f"Error: Please enter an integer between {min_value} and {max_value}.")
            except ValueError:
                print("Error: Invalid input. Please enter an integer.")

    # List all devices to see their indexes
    audio_list = []
    for i in range(pa.get_device_count()):
        dev = pa.get_device_info_by_index(i)
        print(
            i,
            dev['name'],
            dev['maxInputChannels'],
            dev['defaultSampleRate']
        )
        audio_list.append(dev)

    mesg = "Which device is the microphone you are using?"
    device_num = get_valid_integer(mesg, 0, len(audio_list) - 1)

    microphone_channel_num = audio_list[device_num]['maxInputChannels']
    # must pass int type, pyaudio only accepts int type
    microphone_sample_rate = int(audio_list[device_num]['defaultSampleRate'])
    try:
        stream = pa.open(
            format=pyaudio.paInt16,
            channels=microphone_channel_num,
            rate=microphone_sample_rate,
            input=True,
            frames_per_buffer=1024,
            input_device_index=device_num,
        )
        # Save to a valid WAV file

        frames = []
        for _ in range(0, int(microphone_sample_rate / 1024 * 1)):  # Record for 5 seconds
            data = stream.read(1024)
            frames.append(data)
        print("Recording finished.")

        output_filename = "test.wav"
        with wave.open(output_filename, "wb") as wf:
            wf.setnchannels(microphone_channel_num)
            wf.setsampwidth(pa.get_sample_size(pyaudio.paInt16))
            wf.setframerate(microphone_sample_rate)
            wf.writeframes(b"".join(frames))
        print("Recorded some data:", len(data))
        print("Looks Good To Me.")
        stream.close()
        pa.terminate()
    except Exception as e:
        print("Something went wrong. Can not open the audio device")
        print(e)

    return {
        "device_num": device_num,
        "microphone_channel_num": microphone_channel_num,
        "microphone_sample_rate": microphone_sample_rate,
    }

if __name__ == "__main__":
    print(get_microphone())