#if !TARGET_OS_OSX
#import <UIKit/UIKit.h>
#endif

#import <React/RCTBridge.h>
#import <React/RCTLog.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTUtils.h>

#import "WebRTCModule+RTCPeerConnection.h"
#import "WebRTCModule.h"

static WebRTCModule *globalSelf;

@interface WebRTCModule ()
@property (nonatomic, strong) AVAudioEngine *audioEngine;
@property (nonatomic, strong) AVAudioPCMBuffer *inputBuffer;
@end

@implementation WebRTCModule

+ (BOOL)requiresMainQueueSetup {
    return NO;
}

- (void)dealloc {
    [_localTracks removeAllObjects];
    _localTracks = nil;
    [_localStreams removeAllObjects];
    _localStreams = nil;

    for (NSNumber *peerConnectionId in _peerConnections) {
        RTCPeerConnection *peerConnection = _peerConnections[peerConnectionId];
        peerConnection.delegate = nil;
        [peerConnection close];
    }
    [_peerConnections removeAllObjects];

    _peerConnectionFactory = nil;
}


//- (void) audioCallbackFunction :(AudioBufferList *)bufferList :(UInt32)framesCount {
//    // Do something with the audio buffer list
//}

void audioCallbackFunction(AudioBufferList *bufferList, UInt32 frames) {
    // Your audio processing code here
    [globalSelf resampleAudio:bufferList :frames];
    
}

// Define the callback function for the sample rate change
void sampleRateChangeCallbackFunction(float sampleRate) {
    // Do something with the new sample rate
}

- (void)resampleAudio:(AudioBufferList *)audioBufferList :(UInt32)inNumberFrames {
    
    if(self.pitchModificationEnabled != true) {
        return;
    }
    
    for (UInt32 i = 0; i < audioBufferList->mNumberBuffers; i++) {
            AudioBuffer buffer = audioBufferList->mBuffers[i];
            SInt16 *data = (SInt16 *)buffer.mData;
            SInt16 *resampledData = (SInt16 *)malloc(buffer.mDataByteSize);

            UInt32 outputFrames = (UInt32)(inNumberFrames / self.pitchFactor);

            for (UInt32 j = 0; j < outputFrames - 1; j++) {
                Float64 inputPosition = j * self.pitchFactor;
                UInt32 inputPositionFloor = (UInt32)floor(inputPosition);
                SInt16 valueA = data[inputPositionFloor];
//                Float32 valueB = data[inputPositionFloor + 1];
//                Float64 fraction = inputPosition - inputPositionFloor;
//
//                resampledData[j] = valueA + (valueB - valueA) * fraction;
                resampledData[j] = valueA;
            }
            

            memcpy(data, resampledData, outputFrames * sizeof(SInt16));
            buffer.mDataByteSize = outputFrames * sizeof(SInt16);
            free(resampledData);
        }
//    [self->_peerConnectionFactory sendBuffer:*audioBufferList];
}

- (instancetype)init {
    return [self initWithEncoderFactory:nil decoderFactory:nil];
}

- (instancetype)initWithEncoderFactory:(nullable id<RTCVideoEncoderFactory>)encoderFactory
                        decoderFactory:(nullable id<RTCVideoDecoderFactory>)decoderFactory {
    self = [super init];
    if (self) {
        _audioEngine = [[AVAudioEngine alloc] init];
        _pitchFactor = 1.1f;
        if (encoderFactory == nil) {
            encoderFactory = [[RTCDefaultVideoEncoderFactory alloc] init];
        }
        if (decoderFactory == nil) {
            decoderFactory = [[RTCDefaultVideoDecoderFactory alloc] init];
        }
        _encoderFactory = encoderFactory;
        _decoderFactory = decoderFactory;

        _peerConnectionFactory = [[RTCPeerConnectionFactory alloc] initWithEncoderFactory:encoderFactory
                                                                           decoderFactory:decoderFactory];
        
        globalSelf = self;
        [_peerConnectionFactory setAUCallback:&audioCallbackFunction sampleRateChangeCallbackParam:&sampleRateChangeCallbackFunction];
        

        _peerConnections = [NSMutableDictionary new];
        _localStreams = [NSMutableDictionary new];
        _localTracks = [NSMutableDictionary new];

        dispatch_queue_attr_t attributes =
            dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, -1);
        _workerQueue = dispatch_queue_create("WebRTCModule.queue", attributes);
    }

    return self;
}

- (RTCMediaStream *)streamForReactTag:(NSString *)reactTag {
    RTCMediaStream *stream = _localStreams[reactTag];
    if (!stream) {
        for (NSNumber *peerConnectionId in _peerConnections) {
            RTCPeerConnection *peerConnection = _peerConnections[peerConnectionId];
            stream = peerConnection.remoteStreams[reactTag];
            if (stream) {
                break;
            }
        }
    }
    return stream;
}

RCT_EXPORT_MODULE();

- (dispatch_queue_t)methodQueue {
    return _workerQueue;
}

- (NSArray<NSString *> *)supportedEvents {
    return @[
        kEventPeerConnectionSignalingStateChanged,
        kEventPeerConnectionStateChanged,
        kEventPeerConnectionOnRenegotiationNeeded,
        kEventPeerConnectionIceConnectionChanged,
        kEventPeerConnectionIceGatheringChanged,
        kEventPeerConnectionGotICECandidate,
        kEventPeerConnectionDidOpenDataChannel,
        kEventDataChannelDidChangeBufferedAmount,
        kEventDataChannelStateChanged,
        kEventDataChannelReceiveMessage,
        kEventMediaStreamTrackMuteChanged,
        kEventMediaStreamTrackEnded,
        kEventPeerConnectionOnRemoveTrack,
        kEventPeerConnectionOnTrack
    ];
}

@end
