from typing import List
from pydantic import BaseModel, field_validator

# Discrete TX power levels (dBm) supported by the Nordic SoftDevice Controller
# for the nRF radio PA. The HCI controller will clamp requested values to the
# nearest supported step. The maximum is bounded by CONFIG_BT_CTLR_TX_PWR_*
# in the hci_uart firmware (currently +8 dBm).
TX_POWER_VALID = [8, 7, 6, 5, 4, 3, 2, 0, -4, -8, -12, -16, -20]

# Define some base to hold the relevant parameters
class AuracastQoSConfig(BaseModel):
    iso_int_multiple_10ms: int
    number_of_retransmissions: int
    max_transport_latency_ms: int

class AuracastQosRobust(AuracastQoSConfig):
    iso_int_multiple_10ms: int = 1
    number_of_retransmissions:int = 4 #4
    max_transport_latency_ms:int = 43 #varies from the default value in bumble (was 65)

class AuracastQosFast(AuracastQoSConfig):
    iso_int_multiple_10ms: int = 1
    number_of_retransmissions:int = 2
    max_transport_latency_ms:int = 22


class AuracastGlobalConfig(BaseModel):
    qos_config: AuracastQoSConfig =  AuracastQosRobust()
    debug: bool = False
    device_name: str = 'Auracaster'
    transport: str = ''
    auracast_device_address: str = 'F0:F1:F2:F3:F4:F5'
    auracast_sampling_rate_hz: int = 16000
    octets_per_frame: int = 40 #48kbps@24kHz # bitrate = octets_per_frame * 8 / frame len
    frame_duration_us: int = 10000
    presentation_delay_us: int = 40000
    # LE Audio: Broadcast Audio Immediate Rendering (metadata type 0x09)
    # When true, include a zero-length LTV with type 0x09 in the subgroup metadata
    # so receivers may render earlier than the presentation delay for lower latency.
    immediate_rendering: bool = False
    assisted_listening_stream: bool = False
    # Bluetooth advertising TX power for this radio in dBm (per advertising set).
    # Sent through HCI_LE_Set_Extended_Advertising_Parameters; the SDC clamps to
    # nearest supported hardware step and propagates to primary/secondary adv,
    # the periodic advertising train and the BIS ISO PDUs.
    advertising_tx_power: int = 8

    @field_validator('advertising_tx_power')
    @classmethod
    def _snap_tx_power(cls, v: int) -> int:
        # Snap to the nearest supported discrete step in TX_POWER_VALID.
        if v in TX_POWER_VALID:
            return v
        return min(TX_POWER_VALID, key=lambda s: abs(s - v))

# "Audio input. "
# "'device' -> use the host's default sound input device, "
# "'device:<DEVICE_ID>' -> use one of the host's sound input devices "
# "(specify 'device:?' to get a list of available sound input devices), "
# "'stdin' -> receive audio from stdin as int16 PCM, "
# "'file:<filename> -> read audio from a .wav or raw int16 PCM file. "
class AuracastBigConfig(BaseModel):
    id: int = 123456
    random_address: str = 'F1:F1:F2:F3:F4:F5'
    code: str | None = None # Broadcast_Code – a 16-octet parameter provided by the Host
    language: str = 'eng' # See: https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes
    name: str = 'Broadcast0'
    program_info: str = 'Some Announcements'
    audio_source: str = 'file:./auracast/announcement_48_10_96000_en.wav'
    input_format: str = 'auto'
    loop: bool = True
    precode_wav: bool = False
    iso_que_len: int = 64
    num_bis: int = 1  # 1 = mono (FRONT_LEFT), 2 = stereo (FRONT_LEFT + FRONT_RIGHT)

class AuracastBigConfigDeu(AuracastBigConfig):
    id: int = 12
    random_address: str = 'F1:F1:F2:F3:F4:F5'
    name: str = 'Hörsaal A'
    language: str ='deu'
    program_info: str = 'Vorlesung DE'
    audio_source: str = 'file:./testdata/wave_particle_5min_de.lc3'

class AuracastBigConfigEng(AuracastBigConfig):
    id: int = 123
    random_address: str = 'F2:F1:F2:F3:F4:F5'
    name: str  = 'Lecture Hall A'
    language: str ='eng'
    program_info: str = 'Lecture EN'
    audio_source: str  = 'file:./testdata/wave_particle_5min_en.lc3'

class AuracastBigConfigFra(AuracastBigConfig):
    id: int = 1234
    random_address: str = 'F3:F1:F2:F3:F4:F5'
    # French
    name: str  = 'Auditoire A'
    language: str ='fra'
    program_info: str = 'Auditoire FR'
    audio_source: str  = 'file:./testdata/wave_particle_5min_fr.lc3'

class AuracastBigConfigSpa(AuracastBigConfig):
    id: int =12345
    random_address: str = 'F4:F1:F2:F3:F4:F5'
    name: str  = 'Auditorio A'
    language: str ='spa'
    program_info: str = 'Auditorio ES'
    audio_source: str  = 'file:./testdata/wave_particle_5min_es.lc3'

class AuracastBigConfigIta(AuracastBigConfig):
    id: int =1234567
    random_address: str = 'F5:F1:F2:F3:F4:F5'
    name: str  = 'Aula A'
    language: str ='ita'
    program_info: str = 'Aula IT'
    audio_source: str  = 'file:./testdata/wave_particle_5min_it.lc3'


class AuracastBigConfigPol(AuracastBigConfig):
    id: int =12345678
    random_address: str = 'F6:F1:F2:F3:F4:F5'
    name: str  = 'Sala Wykładowa'
    language: str ='pol'
    program_info: str = 'Sala Wykładowa PL'
    audio_source: str  = 'file:./testdata/wave_particle_5min_pl.lc3'


class AuracastConfigGroup(AuracastGlobalConfig):
    bigs: List[AuracastBigConfig] = [
        AuracastBigConfigDeu(),
    ]
    analog_gain_db_left: float = 0.0  # ADC gain level for analog mode left channel (-12 to 18 dB)
    analog_gain_db_right: float = 0.0  # ADC gain level for analog mode right channel (-12 to 18 dB)
