#
#    Copyright (c) 2021-2022 Project CHIP Authors
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
#
import ctypes
from enum import Enum
from typing import Optional

from chip.configuration import GetCommissionerCAT, GetLocalNodeId
from chip.internal.types import NetworkCredentialsRequested, OperationalCredentialsRequested, PairingComplete
from chip.native import GetLibraryHandle, NativeLibraryHandleMethodArguments

# Not using c_void_p directly is IMPORTANT. Python auto-casts c_void_p
# to intergers and this can cause 32/64 bit issues.


class Commissioner_p(ctypes.c_void_p):
    pass


class ThreadBlob_p(ctypes.c_void_p):
    pass


@NetworkCredentialsRequested
def OnNetworkCredentialsRequested():
    GetCommissioner()._OnNetworkCredentialsRequested()


@OperationalCredentialsRequested
def OnOperationalCredentialsRequested(csr, csr_length):
    GetCommissioner()._OnOperationalCredentialsRequested(
        ctypes.string_at(csr, csr_length))


@PairingComplete
def OnPairingComplete(err: int):
    GetCommissioner()._OnPairingComplete(err)


class PairingState(Enum):
    """States throughout a pairing flow.

    Devices generally go through:
      initialized -> pairing -> netcreds -> opcreds -> done (initialized)

    where network credentials may be skipped if device is already on the network.
    """
    INITIALIZED = 0
    PAIRING = 1
    NEEDS_NETCREDS = 2
    NEEDS_OPCREDS = 3


class Commissioner:
    """Commissioner wraps the DeviceCommissioner native class.


    The commissioner is a DeviceController that supports pairing. Since the device
    controller supports multiple devices, this class is expected to be used
    as a singleton

    """

    def __init__(self, handle: ctypes.CDLL, native: Commissioner_p):
        self._handle = handle
        self._native = native
        self.pairing_state = PairingState.INITIALIZED
        self.on_pairing_complete = None

    def BlePair(self, remoteDeviceId: int, pinCode: int, discriminator: int):
        result = self._handle.pychip_internal_Commissioner_BleConnectForPairing(
            self._native, remoteDeviceId, pinCode, discriminator)
        if result != 0:
            raise Exception("Failed to pair. CHIP Error code %d" % result)

        self.pairing_state = PairingState.PAIRING

    def Unpair(self, remoteDeviceId: int):
        result = self._handle.pychip_internal_Commissioner_Unpair(
            self._native, remoteDeviceId)
        if result != 0:
            raise Exception("Failed to unpair. CHIP Error code %d" % result)

    def _OnPairingComplete(self, err: int):
        self.pairing_state = PairingState.INITIALIZED
        if self.on_pairing_complete:
            self.on_pairing_complete(err)


def _SetNativeCallSignatues(handle: ctypes.CDLL):
    """Sets up the FFI types for the cdll handle."""
    setter = NativeLibraryHandleMethodArguments(handle)

    setter.Set('pychip_internal_Commissioner_New',
               Commissioner_p, [ctypes.c_uint64, ctypes.c_uint32])
    setter.Set('pychip_internal_Commissioner_Unpair',
               ctypes.c_uint32, [Commissioner_p, ctypes.c_uint64])
    setter.Set('pychip_internal_Commissioner_BleConnectForPairing',
               ctypes.c_uint32, [Commissioner_p, ctypes.c_uint64, ctypes.c_uint32, ctypes.c_uint16])

    setter.Set('pychip_internal_PairingDelegate_SetPairingCompleteCallback', None, [
               PairingComplete])


commissionerSingleton: Optional[Commissioner] = None


def GetCommissioner() -> Commissioner:
    """Gets a reference to the global commissioner singleton.

    Uses the configuration GetLocalNodeId() and GetCommissionerCAT().
    """

    global commissionerSingleton

    if commissionerSingleton is None:
        handle = GetLibraryHandle()
        _SetNativeCallSignatues(handle)

        native = handle.pychip_internal_Commissioner_New(
            GetLocalNodeId(), GetCommissionerCAT())
        if not native:
            raise Exception('Failed to create commissioner object.')

        handle.pychip_internal_PairingDelegate_SetPairingCompleteCallback(
            OnPairingComplete)

        commissionerSingleton = Commissioner(handle, native)

    return commissionerSingleton
