import win32con
import win32gui
import win32api
import ctypes
from ctypes import wintypes
import pyaudio
import wave
import os

DBT_DEVTYP_DEVICEINTERFACE = 5

new_device = False
hdev_notify = None
hwnd = None
wc = win32gui.WNDCLASS()

audio_clip_path = "assets/audio/CantinaBand3.wav"
if os.path.exists("_Internal/") is True:
    audio_clip_path = "_Internal/" + audio_clip_path

def wnd_proc(handle, message, w_param, l_param):
    global new_device
    if message == win32con.WM_DEVICECHANGE:
        win32gui.UnregisterDeviceNotification(hdev_notify)
        win32gui.DestroyWindow(hwnd)
        win32gui.UnregisterClass(wc.lpszClassName, None)
        new_device = True
        return win32gui.DefWindowProc(handle, message, w_param, l_param)
    else:
        return win32gui.DefWindowProc(handle, message, w_param, l_param)


def device_change_listener():
    global hdev_notify, hwnd, wc, new_device

    wc = win32gui.WNDCLASS()
    wc.lpfnWndProc = wnd_proc
    wc.lpszClassName = 'DeviceChangeMonitor'
    hinst = wc.hInstance = win32api.GetModuleHandle(None)
    class_atom = win32gui.RegisterClass(wc)
    hwnd = win32gui.CreateWindow(class_atom, "Device Change", 0, 0, 0, 0, 0, 0, 0, hinst, None)

    class DEV_BROADCAST_DEVICEINTERFACE(ctypes.Structure):
        _fields_ = [("dbch_size", wintypes.DWORD),
                    ("dbch_devicetype", wintypes.DWORD),
                    ("dbch_reserved", wintypes.DWORD),
                    ("dbcc_classguid", ctypes.c_byte * 16),
                    ("dbcc_name", ctypes.c_wchar * 256)]

    dbi = DEV_BROADCAST_DEVICEINTERFACE()
    dbi.dbch_size = ctypes.sizeof(DEV_BROADCAST_DEVICEINTERFACE)
    dbi.dbch_devicetype = DBT_DEVTYP_DEVICEINTERFACE
    hdev_notify = win32gui.RegisterDeviceNotification(hwnd, dbi, win32con.DEVICE_NOTIFY_WINDOW_HANDLE)

    try:
        while new_device is False:
            win32gui.PumpWaitingMessages()
    except KeyboardInterrupt:
        win32gui.UnregisterDeviceNotification(hdev_notify)
        win32gui.DestroyWindow(hwnd)
        win32gui.UnregisterClass(wc.lpszClassName, None)


def play_audio():
    # Play a wav file from the local dir
    chunk = 1024
    f = None
    p = None
    stream = None
    
    try:
        f = wave.open(audio_clip_path, "rb")
        p = pyaudio.PyAudio()
        stream = p.open(format=p.get_format_from_width(f.getsampwidth()),
                        channels=f.getnchannels(),
                        rate=f.getframerate(),
                        output=True)
        data = f.readframes(chunk)
        while data:
            stream.write(data)
            data = f.readframes(chunk)
    except Exception as e:
        print(f"Audio playback error: {e}")
        raise  # Re-raise the exception so the calling code can handle it
    finally:
        # Ensure cleanup happens even if an exception occurs
        if stream is not None:
            try:
                stream.stop_stream()
                stream.close()
            except:
                pass
        if p is not None:
            try:
                p.terminate()
            except:
                pass
        if f is not None:
            try:
                f.close()
            except:
                pass


def listen_for_devices():
    device_change_listener()


def check_for_headphones():
    return new_device