"""
Compatibility patch for the `soundcard` library (pinned to 0.4.6).

soundcard's `_AudioClient.__init__` asserts that every device reports a
WAVE_FORMAT_EXTENSIBLE / IEEE-float mix format. Many USB headsets (e.g. JLab,
Jabra) report a plain non-extensible format instead, which crashes recorder
creation with a bare AssertionError — meeting recording would fail on exactly
the devices call users wear.

Fix: instead of trusting the device's mix-format struct, always request plain
WAVE_FORMAT_IEEE_FLOAT (tag 3, cbSize 0) at our own samplerate/channels.
WASAPI shared mode is initialized with the AUTOCONVERTPCM | SRC_DEFAULT_QUALITY
stream flags (soundcard already sets them), so Windows converts from any
device format — verified working on both extensible (Realtek) and
non-extensible (JLab headset) endpoints.
"""
from __future__ import annotations

from loguru import logger


def apply() -> None:
    """Monkeypatch soundcard's _AudioClient.__init__ (idempotent)."""
    import collections.abc

    import soundcard.mediafoundation as mf

    if getattr(mf._AudioClient.__init__, "_voxcast_patched", False):
        return

    _ffi = mf._ffi
    _com = mf._com
    _ole32 = mf._ole32

    def patched_init(self, ptr, samplerate, channels, blocksize,
                     isloopback, exclusive_mode=False):
        self._ptr = ptr

        if isinstance(channels, int):
            self.channelmap = list(range(channels))
        elif isinstance(channels, collections.abc.Iterable):
            self.channelmap = channels
        else:
            raise TypeError('channels must be iterable or integer')

        if list(range(len(set(self.channelmap)))) != sorted(list(set(self.channelmap))):
            raise TypeError('Due to limitations of WASAPI, channel maps on Windows '
                            'must be a combination of `range(0, x)`.')

        if blocksize is None:
            blocksize = self.deviceperiod[0] * samplerate

        ppMixFormat = _ffi.new('WAVEFORMATEXTENSIBLE**')
        hr = self._ptr[0][0].lpVtbl.GetMixFormat(self._ptr[0], ppMixFormat)
        _com.check_error(hr)

        # VoxCast fix: don't assert the device's mix format. Rewrite the
        # request as plain IEEE-float at our rate — shared mode with the
        # AUTOCONVERTPCM stream flag below accepts this on every endpoint.
        nch = len(set(self.channelmap))
        fmt = ppMixFormat[0][0].Format
        fmt.wFormatTag = 0x0003          # WAVE_FORMAT_IEEE_FLOAT
        fmt.cbSize = 0                   # plain WAVEFORMATEX, no extension
        fmt.nChannels = nch
        fmt.nSamplesPerSec = int(samplerate)
        fmt.nAvgBytesPerSec = int(samplerate) * nch * 4
        fmt.nBlockAlign = nch * 4
        fmt.wBitsPerSample = 32

        if exclusive_mode:
            sharemode = _ole32.AUDCLNT_SHAREMODE_EXCLUSIVE
        else:
            sharemode = _ole32.AUDCLNT_SHAREMODE_SHARED
        #             resample   | remix      | better-SRC | nopersist
        streamflags = 0x00100000 | 0x80000000 | 0x08000000 | 0x00080000
        if isloopback:
            streamflags |= 0x00020000  # loopback
        bufferduration = int(blocksize / samplerate * 10000000)  # in hns
        hr = self._ptr[0][0].lpVtbl.Initialize(
            self._ptr[0], sharemode, streamflags, bufferduration, 0,
            ppMixFormat[0], _ffi.NULL)
        _com.check_error(hr)
        _ole32.CoTaskMemFree(ppMixFormat[0])

        self.samplerate = samplerate
        self._idle_start_time = None

    patched_init._voxcast_patched = True
    mf._AudioClient.__init__ = patched_init
    logger.info("soundcard compat patch applied (non-extensible mix formats)")
