# SPDX-FileCopyrightText: 2020 Dan Halbert for Adafruit Industries
#
# SPDX-License-Identifier: MIT

"""
`adafruit_ble_adafruit.tone_service`
================================================================================

BLE access to play tones.

* Author(s): Dan Halbert
"""

__version__ = "0.0.0+auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_BLE_Adafruit.git"

import struct

from _bleio import PacketBuffer

from adafruit_ble.attributes import Attribute
from adafruit_ble.characteristics import Characteristic, ComplexCharacteristic
from adafruit_ble_adafruit.adafruit_service import AdafruitService

try:
    from typing import Optional, Tuple
except ImportError:
    pass


class _TonePacket(ComplexCharacteristic):
    uuid = AdafruitService.adafruit_service_uuid(0xC01)

    format = "<HI"
    format_size = struct.calcsize(format)

    def __init__(self) -> None:
        super().__init__(
            properties=Characteristic.WRITE,
            read_perm=Attribute.NO_ACCESS,
            max_length=self.format_size,
            fixed_length=True,
        )

    def bind(self, service: "ToneService") -> PacketBuffer:
        """Binds the characteristic to the given Service."""
        bound_characteristic = super().bind(service)
        return PacketBuffer(bound_characteristic, buffer_size=1)


class ToneService(AdafruitService):
    """Play tones."""

    uuid = AdafruitService.adafruit_service_uuid(0xC00)
    _tone_packet = _TonePacket()
    """
    Tuple of (frequency: 16 bits, in Hz, duration: 32 bits, in msecs).
    If frequency == 0, a tone being played is turned off.
    if duration == 0, play indefinitely.
    """

    def __init__(self, service: Optional["ToneService"] = None) -> None:
        super().__init__(service=service)
        self._tone_packet_buf = bytearray(_TonePacket.format_size)

    @property
    def tone(self) -> Optional[Tuple[int, int]]:
        """Return (frequency, duration), or None if no value available"""
        buf = self._tone_packet_buf
        if self._tone_packet.readinto(buf) == 0:
            # No new values available.
            return None
        return struct.unpack(_TonePacket.format, buf)

    def play(self, frequency: int, duration: float) -> None:
        """
        Frequency is in Hz. If frequency == 0, a tone being played is turned off.
        Duration is in seconds. If duration == 0, play indefinitely.
        """
        self._tone_packet = struct.pack(
            _TonePacket.format,
            frequency,
            0 if duration == 0 else int(duration * 1000 + 0.5),
        )
