# Path: mppsolar/io/baseio.py
# class BaseIO(ABC):
#     @abstractmethod
#     def send_and_receive(self, *args, **kwargs) -> dict:
#         raise NotImplementedError
# 
#     def connect(self) -> None:
#         log.debug("connect not implemented")
#         return
# 
#     def disconnect(self) -> None:
#         log.debug("disconnect not implemented")
#         return
# 
#     def process_command(self, command, protocol):
#         # Band-aid solution, need to reduce what is sent
#         log.debug(f"Command {command}")
#         full_command = protocol.get_full_command(command)
# 
#         raw_response = self.send_and_receive(
#             command=command,
#             full_command=full_command,
#             protocol=protocol,
#             command_defn=protocol.get_command_defn(command),
#         )
#         log.debug(f"Send and Receive Response {raw_response}")
# 
#         # Handle errors
#         # Maybe there should a decode for ERRORs and WARNINGS...
#         # Some inverters return the command if the command is unknown:
#         if raw_response == full_command:
#             return {
#                 "ERROR": [
#                     f"Inverter returned the command string for {command} - the inverter didnt recognise this command",
#                     "",
#                 ]
#             }
#         # dict is returned on exception
# 
#         if isinstance(raw_response, dict):
#             return raw_response
# 
#         # Decode response
#         decoded_response = protocol.decode(raw_response, command)
#         log.info(f"Decoded response {decoded_response}")
# 
#         return decoded_response
# 
# Path: mppsolar/helpers.py
# def get_kwargs(kwargs, key, default=None):
#     if key not in kwargs or not kwargs[key]:
#         return default
#     return kwargs[key]
# 
# Path: mppsolar/io/jkbledelegate.py
# class jkBleDelegate(btle.DefaultDelegate):
#     """
#     BLE delegate to deal with notifications (information) from the JKBMS device
#     """
# 
#     def __init__(self, jkbleio, protocol, record_type=None):
#         btle.DefaultDelegate.__init__(self)
#         # extra initialisation here
#         self._jkbleio = jkbleio
#         if protocol is None:
#             print("ERROR")
#             exit(1)
#         self._protocol = protocol
#         self._record_type = record_type
#         self.notificationData = bytearray()
# 
#     def handleNotification(self, handle, data):
#         # handle is the handle of the characteristic / descriptor that posted the notification
#         # data is the data in this notification - may take multiple notifications to get all of a message
#         log.debug("From handle: {:#04x} Got {} bytes of data".format(handle, len(data)))
#         self.notificationData += bytearray(data)
#         if not self._protocol.is_record_start(self.notificationData):
#             log.debug(f"Not valid start of record - wiping data {self.notificationData}")
#             self.notificationData = bytearray()
#         if not self._protocol.is_record_correct_type(self.notificationData, self._record_type):
#             log.debug(f"Not expected type of record - wiping data {self.notificationData}")
#             # self.notificationData = bytearray()
#         if self._protocol.is_record_complete(self.notificationData):
#             self._jkbleio.record = self.notificationData
#             log.debug("record complete")
#             self.notificationData = bytearray()


from bluepy import btle
from .baseio import BaseIO
from ..helpers import get_kwargs
from .jkbledelegate import jkBleDelegate
import logging



log = logging.getLogger("JkBleIO")

getInfo = b"\xaa\x55\x90\xeb\x97\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11"
# getInfo = b"\xaa\x55\x90\xeb\x97\x00\xdf\x52\x88\x67\x9d\x0a\x09\x6b\x9a\xf6\x70\x9a\x17\xfd"


class JkBleIO(BaseIO):
    def __init__(self, device_path) -> None:
        self._device = None
        self._device_path = device_path
        self.maxConnectionAttempts = 3
        self.record = None

    def send_and_receive(self, *args, **kwargs) -> dict:
        # Send the full command via the communications port
        command = get_kwargs(kwargs, "command")

# Path: mppsolar/io/baseio.py
# class BaseIO(ABC):
#     @abstractmethod
#     def send_and_receive(self, *args, **kwargs) -> dict:
#         raise NotImplementedError
# 
#     def connect(self) -> None:
#         log.debug("connect not implemented")
#         return
# 
#     def disconnect(self) -> None:
#         log.debug("disconnect not implemented")
#         return
# 
#     def process_command(self, command, protocol):
#         # Band-aid solution, need to reduce what is sent
#         log.debug(f"Command {command}")
#         full_command = protocol.get_full_command(command)
# 
#         raw_response = self.send_and_receive(
#             command=command,
#             full_command=full_command,
#             protocol=protocol,
#             command_defn=protocol.get_command_defn(command),
#         )
#         log.debug(f"Send and Receive Response {raw_response}")
# 
#         # Handle errors
#         # Maybe there should a decode for ERRORs and WARNINGS...
#         # Some inverters return the command if the command is unknown:
#         if raw_response == full_command:
#             return {
#                 "ERROR": [
#                     f"Inverter returned the command string for {command} - the inverter didnt recognise this command",
#                     "",
#                 ]
#             }
#         # dict is returned on exception
# 
#         if isinstance(raw_response, dict):
#             return raw_response
# 
#         # Decode response
#         decoded_response = protocol.decode(raw_response, command)
#         log.info(f"Decoded response {decoded_response}")
# 
#         return decoded_response
# 
# Path: mppsolar/helpers.py
# def get_kwargs(kwargs, key, default=None):
#     if key not in kwargs or not kwargs[key]:
#         return default
#     return kwargs[key]
# 
# Path: mppsolar/io/jkbledelegate.py
# class jkBleDelegate(btle.DefaultDelegate):
#     """
#     BLE delegate to deal with notifications (information) from the JKBMS device
#     """
# 
#     def __init__(self, jkbleio, protocol, record_type=None):
#         btle.DefaultDelegate.__init__(self)
#         # extra initialisation here
#         self._jkbleio = jkbleio
#         if protocol is None:
#             print("ERROR")
#             exit(1)
#         self._protocol = protocol
#         self._record_type = record_type
#         self.notificationData = bytearray()
# 
#     def handleNotification(self, handle, data):
#         # handle is the handle of the characteristic / descriptor that posted the notification
#         # data is the data in this notification - may take multiple notifications to get all of a message
#         log.debug("From handle: {:#04x} Got {} bytes of data".format(handle, len(data)))
#         self.notificationData += bytearray(data)
#         if not self._protocol.is_record_start(self.notificationData):
#             log.debug(f"Not valid start of record - wiping data {self.notificationData}")
#             self.notificationData = bytearray()
#         if not self._protocol.is_record_correct_type(self.notificationData, self._record_type):
#             log.debug(f"Not expected type of record - wiping data {self.notificationData}")
#             # self.notificationData = bytearray()
#         if self._protocol.is_record_complete(self.notificationData):
#             self._jkbleio.record = self.notificationData
#             log.debug("record complete")
#             self.notificationData = bytearray()


# Path: mppsolar/io/jkbleio.py
from bluepy import btle
from .baseio import BaseIO
from ..helpers import get_kwargs
from .jkbledelegate import jkBleDelegate
import logging




log = logging.getLogger("JkBleIO")

getInfo = b"\xaa\x55\x90\xeb\x97\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x11"
# getInfo = b"\xaa\x55\x90\xeb\x97\x00\xdf\x52\x88\x67\x9d\x0a\x09\x6b\x9a\xf6\x70\x9a\x17\xfd"


class JkBleIO(BaseIO):
    def __init__(self, device_path) -> None:
        self._device = None
        self._device_path = device_path
        self.maxConnectionAttempts = 3
        self.record = None

    def send_and_receive(self, *args, **kwargs) -> dict:
        # Send the full command via the communications port
        command = get_kwargs(kwargs, "command")

        protocol = get_kwargs(kwargs, "protocol")