//
// © 2019-2020 Qualcomm Technologies, Inc. and/or its subsidiaries. All rights reserved.
//

#import "IoTZigbeeState.h"
#import "IoTGlobals.h"
#import "IoTWrappedRepresentation.h"
#import "IoTResourceAttributes.h"
#import "IoTProperties.h"

@interface IoTZigbeeState()

@property (nonatomic, strong, readonly) dispatch_queue_t syncQueue;
@property (nonatomic, copy, readwrite, nullable) IoTZigbeeAttr *zbAttribute;
@property (nonatomic, assign, readwrite) IoTZigbeeAdapterState adapterStateInternal;
@property (nonatomic, assign, readwrite) IoTCoordinatorState coordinatorStateInternal;
@property (nonatomic, assign, readwrite) BOOL scanningInternal;
@property (nonatomic, copy, readwrite) NSArray<IoTZbDeviceAttr *> *joinedDevicesInternal;

@end

@implementation IoTZigbeeState

- (instancetype)init
{
    self = [super init];
    if (self) {
        // We use a separate queue to prevent deadlock.
        self->_syncQueue = dispatch_queue_create("com.qualcomm.qti.IoTBluetoothState.syncQueue", DISPATCH_QUEUE_CONCURRENT);
        self->_adapterStateInternal = IoTZigbeeAdapterStateUnknown;
        self->_coordinatorStateInternal = IoTCoordinatorStateUnknown;
        self->_scanningInternal = NO;
        self->_joinedDevicesInternal = @[];
    }
    return self;
}

- (void)updateWithAttribute:(IoTZigbeeAttr *)zbAttr
{
    makeWeak(self)
    dispatch_barrier_async(self.syncQueue, ^{
        makeStrongAndReturnIfNil(self)
        self.zbAttribute = [zbAttr copy];
        if (zbAttr) {
            self.adapterStateInternal = self.zbAttribute.adapterState;
            self.coordinatorStateInternal = self.zbAttribute.coordinatorState;
            self.joinedDevicesInternal = self.zbAttribute.joinedDevices;
            self.scanningInternal = NO;
        }
    });
}

- (NSArray<NSString *> *)updateWithWrapper:(IoTWrappedRepresentation *)wrapper
{
    NSArray *keys = [wrapper keys];
    NSMutableArray<NSString *> *moddedKeys = [keys mutableCopy];

    dispatch_assert_queue_not(self.syncQueue);
    dispatch_sync(self.syncQueue, ^{
        [self.zbAttribute unpack:wrapper];

        // We need to infer some state from other responses.
        if ([keys containsObject:[NSString stringWithUTF8String:kAdapterState]]) {
            if (self.zbAttribute.adapterState != IoTZigbeeAdapterStateUnknown) {
                self.adapterStateInternal = self.zbAttribute.adapterState;
                if (self.zbAttribute.adapterState == IoTZigbeeAdapterStateDisabled) {
                    self.scanningInternal = NO;
   //                 self.joinedDevicesInternal = @[];
                    self.coordinatorStateInternal = IoTCoordinatorStateNotNominated;
                    [moddedKeys addObject:[NSString stringWithUTF8String:kCoordinatorState]];
    //                [moddedKeys addObject:[NSString stringWithUTF8String:kJoinedDevices]];
                }
            }
        }

        if ([keys containsObject:[NSString stringWithUTF8String:kCoordinatorState]]) {
            if (self.zbAttribute.coordinatorState != IoTCoordinatorStateUnknown) {
                self.coordinatorStateInternal = self.zbAttribute.coordinatorState;
            }
        }
        if ([keys containsObject:[NSString stringWithUTF8String:kJoinedDevices]]) {
            self.joinedDevicesInternal = [self.zbAttribute.joinedDevices copy];
            if ((self.joinedDevicesInternal.count > 0) &&
                (self.adapterStateInternal == IoTZigbeeAdapterStateEnabled) &&
                (self.coordinatorStateInternal != IoTCoordinatorStateNominated)) {
	//			self.coordinatorStateInternal = IoTCoordinatorStateNominated;
     //           [moddedKeys addObject:[NSString stringWithUTF8String:kCoordinatorState]];
            }
        }
        if ([keys containsObject:[NSString stringWithUTF8String:kSignal]]) {
            if (self.zbAttribute.signal.signalName == IoTSignalNameNetworkFormed) {
                // IoTSignalNameNetworkJoined,) {
                self.coordinatorStateInternal = IoTCoordinatorStateNominated;
                [moddedKeys addObject:[NSString stringWithUTF8String:kCoordinatorState]];
            }
        }
        if ([keys containsObject:[NSString stringWithUTF8String:kError]]) {
            [self handleZBError: moddedKeys];
        }
    });

    return moddedKeys;
}

- (void)handleZBError:(NSMutableArray<NSString *> *)keys;
{
    dispatch_assert_queue(self.syncQueue);

    NSString *errorReason = self.zbAttribute.errorReason;
    NSLog (@"ZB Error: %@", errorReason);
}

- (BOOL)supported
{
    __block BOOL supported = NO;
    dispatch_sync(self.syncQueue, ^{
        supported = self.zbAttribute != nil;
    });
    return supported;
}

- (IoTZigbeeAdapterState)adapterState
{
    __block IoTZigbeeAdapterState state = IoTZigbeeAdapterStateUnknown;
    dispatch_sync(self.syncQueue, ^{
        state = self.adapterStateInternal;
    });
    return state;
}

- (IoTCoordinatorState)coordinatorState
{
    __block IoTCoordinatorState state = IoTCoordinatorStateUnknown;
    dispatch_sync(self.syncQueue, ^{
        state = self.coordinatorStateInternal;
    });
    return state;
}

- (NSArray<IoTZbDeviceAttr *> *)joinedDevices
{
    __block NSArray<IoTZbDeviceAttr *> *joined = @[];
    dispatch_sync(self.syncQueue, ^{
        joined = [self.joinedDevicesInternal copy] ?: @[];
    });
    return joined;
}

- (IoTJoiningState)joiningState;{
    return self.zbAttribute.joiningState;
}

@end
