"""
Виртуальный канал связи SDR Rover Link.

Имитирует:
1. Полную потерю пакета.
2. Случайное изменение отдельных битов.
"""

import random


def transmit(
    packet: bytes,
    drop_probability: float,
    bit_error_probability: float,
    random_generator: random.Random,
):
    """
    Передать пакет через виртуальный канал.

    Возвращает:
        received_packet:
            Пакет после прохождения канала.
            None означает полную потерю пакета.

        flipped_bits:
            Количество изменённых битов.
    """

    if not isinstance(packet, (bytes, bytearray)):
        raise TypeError(
            "packet должен иметь тип bytes или bytearray"
        )

    if not 0.0 <= drop_probability <= 1.0:
        raise ValueError(
            "drop_probability должен находиться "
            "в диапазоне 0.0...1.0"
        )

    if not 0.0 <= bit_error_probability <= 1.0:
        raise ValueError(
            "bit_error_probability должен находиться "
            "в диапазоне 0.0...1.0"
        )

    # Решаем, потерян ли пакет полностью.
    if random_generator.random() < drop_probability:
        return None, 0

    corrupted_packet = bytearray(packet)
    flipped_bits = 0

    # Перебираем каждый байт.
    for byte_index in range(len(corrupted_packet)):

        # В каждом байте восемь битов.
        for bit_index in range(8):

            if (
                random_generator.random()
                < bit_error_probability
            ):
                bit_mask = 1 << bit_index

                # XOR меняет выбранный бит:
                # 0 → 1 или 1 → 0.
                corrupted_packet[byte_index] ^= bit_mask

                flipped_bits += 1

    return bytes(corrupted_packet), flipped_bits