//
// Copyright 2025 Alibaba Cloud 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 "AlibabaCloudRUMBridge.h"
#if __has_include(<AlibabaCloud/AlibabaCloudRUMSDK.h>)
    #import <AlibabaCloud/AlibabaCloudRUMSDK.h>
#else
    // Placeholder for IDE - actual SDK will be linked during build
    @interface AlibabaCloudRUMSDK : NSObject
    + (void)setDebuggable:(BOOL)debuggable;
    + (BOOL)start:(NSString *)configAddress workspace:(NSString *)workspace serviceId:(NSString *)serviceId;
    + (BOOL)stop;
    + (BOOL)isStarted;
    + (void)setEnvironment:(NSString *)env;
    + (void)setAppName:(NSString *)name;
    + (void)setAppVersion:(NSString *)version;
    + (void)setChannel:(NSString *)channel;
    + (void)setUserId:(NSString *)userId;
    + (void)setUserName:(NSString *)userName;
    + (NSString *)deviceId;
    + (void)reportException:(NSString *)exceptionType causeBy:(NSString *)causeBy errorDump:(NSString *)errorDump language:(NSString *)language;
    + (BOOL)reportCustomResource:(NSString *)type success:(BOOL)success url:(NSString *)url method:(NSString *)method statusCode:(NSInteger)code errorMessage:(NSString *)errorMessage provider:(NSString *)provider tracing:(id)tracing measuring:(id)measuring;
    + (void)setCustomEvent:(NSString *)name type:(NSString *)type group:(NSString *)group snapshots:(NSString *)snapshots value:(double)value info:(NSDictionary *)info;
    + (void)setCustomLog:(NSString *)logInfo name:(NSString *)name type:(NSString *)type snapshots:(NSString *)snapshots level:(NSString *)level info:(NSDictionary *)info;
    + (void)reportView:(NSString *)viewId loadTime:(NSInteger)loadTime enter:(BOOL)enter name:(NSString *)name method:(NSString *)method map:(NSDictionary *)map type:(NSString *)type;
    @end
    
    typedef NS_ENUM(NSInteger, AlibabaCloudTraceProtocol) {
        AlibabaCloud_W3C,
        AlibabaCloud_SkywalkingV3
    };
    
    @interface AlibabaCloudTraceContext : NSObject
    + (instancetype)contextWithTraceId:(NSString *)traceId spanId:(NSString *)spanId protocol:(AlibabaCloudTraceProtocol)protocol;
    + (instancetype)contextWithTraceId:(NSString *)traceId spanId:(NSString *)spanId parentSpanId:(NSString *)parentSpanId sampled:(BOOL)sampled protocol:(AlibabaCloudTraceProtocol)protocol;
    @end
    
    @interface AlibabaCloudResourceMeasuring : NSObject
    @property(atomic, assign) NSUInteger duration;
    @property(atomic, assign) NSUInteger size;
    @property(atomic, assign) NSUInteger connectDuration;
    @property(atomic, assign) NSUInteger sslDuration;
    @property(atomic, assign) NSUInteger dnsDuration;
    @property(atomic, assign) NSUInteger redirectDuration;
    @property(atomic, assign) NSUInteger firstByteDuration;
    @property(atomic, assign) NSUInteger downloadDuration;
    + (instancetype)measuring;
    @end
#endif

// Helper function to convert C string to NSString
static NSString* CreateNSString(const char* cString) {
    if (cString == NULL) {
        return nil;
    }
    return [NSString stringWithUTF8String:cString];
}

// Helper function to convert NSString to C string (caller must free)
static const char* MakeCString(NSString* nsString) {
    if (nsString == nil) {
        return NULL;
    }
    const char* cString = [nsString UTF8String];
    if (cString == NULL) {
        return NULL;
    }
    char* buffer = (char*)malloc(strlen(cString) + 1);
    strcpy(buffer, cString);
    return buffer;
}

#pragma mark - SDK Initialization and Configuration

void AlibabaCloudRUMSDK_setDebuggable(bool debuggable) {
    [AlibabaCloudRUMSDK setDebuggable:debuggable];
}

bool AlibabaCloudRUMSDK_start(const char* configAddress, const char* workspace, const char* serviceId) {
    NSString* nsConfigAddress = CreateNSString(configAddress);
    NSString* nsWorkspace = CreateNSString(workspace);
    NSString* nsServiceId = CreateNSString(serviceId);
    
    BOOL result = [AlibabaCloudRUMSDK start:nsConfigAddress workspace:nsWorkspace serviceId:nsServiceId];
    return result;
}

bool AlibabaCloudRUMSDK_stop(void) {
    return [AlibabaCloudRUMSDK stop];
}

bool AlibabaCloudRUMSDK_isStarted(void) {
    return [AlibabaCloudRUMSDK isStarted];
}

void AlibabaCloudRUMSDK_setEnvironment(const char* env) {
    NSString* nsEnv = CreateNSString(env);
    if (nsEnv != nil) {
        [AlibabaCloudRUMSDK setEnvironment:nsEnv];
    }
}

void AlibabaCloudRUMSDK_setAppName(const char* name) {
    NSString* nsName = CreateNSString(name);
    if (nsName != nil) {
        [AlibabaCloudRUMSDK setAppName:nsName];
    }
}

void AlibabaCloudRUMSDK_setAppVersion(const char* version) {
    NSString* nsVersion = CreateNSString(version);
    if (nsVersion != nil) {
        [AlibabaCloudRUMSDK setAppVersion:nsVersion];
    }
}

void AlibabaCloudRUMSDK_setChannel(const char* channel) {
    NSString* nsChannel = CreateNSString(channel);
    if (nsChannel != nil) {
        [AlibabaCloudRUMSDK setChannel:nsChannel];
    }
}

void AlibabaCloudRUMSDK_setUserId(const char* userId) {
    NSString* nsUserId = CreateNSString(userId);
    if (nsUserId != nil) {
        [AlibabaCloudRUMSDK setUserId:nsUserId];
    }
}

void AlibabaCloudRUMSDK_setUserName(const char* userName) {
    NSString* nsUserName = CreateNSString(userName);
    if (nsUserName != nil) {
        [AlibabaCloudRUMSDK setUserName:nsUserName];
    }
}

const char* AlibabaCloudRUMSDK_deviceId(void) {
    NSString* deviceId = [AlibabaCloudRUMSDK deviceId];
    return MakeCString(deviceId);
}

#pragma mark - RUM Reporting Methods

void AlibabaCloudRUMSDK_reportException(const char* exceptionType, const char* causeBy, const char* errorDump, const char* language) {
    NSString* nsExceptionType = CreateNSString(exceptionType);
    NSString* nsCauseBy = CreateNSString(causeBy);
    NSString* nsErrorDump = CreateNSString(errorDump);
    NSString* nsLanguage = CreateNSString(language);
    
    [AlibabaCloudRUMSDK reportException:nsExceptionType causeBy:nsCauseBy errorDump:nsErrorDump language:nsLanguage];
}

bool AlibabaCloudRUMSDK_reportCustomResource(const char* type, bool success, const char* url, const char* method,
                                              int statusCode, const char* errorMessage, const char* provider,
                                              void* tracing, void* measuring) {
    NSString* nsType = CreateNSString(type);
    NSString* nsUrl = CreateNSString(url);
    NSString* nsMethod = CreateNSString(method);
    NSString* nsErrorMessage = CreateNSString(errorMessage);
    NSString* nsProvider = CreateNSString(provider);
    
    AlibabaCloudTraceContext* tracingContext = (__bridge AlibabaCloudTraceContext*)tracing;
    AlibabaCloudResourceMeasuring* measuringObj = (__bridge AlibabaCloudResourceMeasuring*)measuring;
    
    BOOL result = [AlibabaCloudRUMSDK reportCustomResource:nsType
                                                   success:success
                                                       url:nsUrl
                                                    method:nsMethod
                                                statusCode:statusCode
                                              errorMessage:nsErrorMessage
                                                  provider:nsProvider
                                                   tracing:tracingContext
                                                 measuring:measuringObj];
    return result;
}

void AlibabaCloudRUMSDK_setCustomEvent(const char* name, const char* type, const char* group,
                                        const char* snapshots, double value, void* info) {
    NSString* nsName = CreateNSString(name);
    NSString* nsType = CreateNSString(type);
    NSString* nsGroup = CreateNSString(group);
    NSString* nsSnapshots = CreateNSString(snapshots);
    NSDictionary* nsInfo = (__bridge NSDictionary*)info;
    
    [AlibabaCloudRUMSDK setCustomEvent:nsName
                                  type:nsType
                                 group:nsGroup
                             snapshots:nsSnapshots
                                 value:value
                                  info:nsInfo];
}

void AlibabaCloudRUMSDK_setCustomLog(const char* logInfo, const char* name, const char* type,
                                      const char* snapshots, const char* level, void* info) {
    NSString* nsLogInfo = CreateNSString(logInfo);
    NSString* nsName = CreateNSString(name);
    NSString* nsType = CreateNSString(type);
    NSString* nsSnapshots = CreateNSString(snapshots);
    NSString* nsLevel = CreateNSString(level);
    NSDictionary* nsInfo = (__bridge NSDictionary*)info;
    
    [AlibabaCloudRUMSDK setCustomLog:nsLogInfo
                                name:nsName
                                type:nsType
                           snapshots:nsSnapshots
                               level:nsLevel
                                info:nsInfo];
}

#pragma mark - View Reporting

void AlibabaCloudRUMSDK_reportView(const char* viewId, int loadTime, bool enter, const char* name,
                                    const char* method, void* map, const char* type) {
    NSString* nsViewId = CreateNSString(viewId);
    NSString* nsName = CreateNSString(name);
    NSString* nsMethod = CreateNSString(method);
    NSString* nsType = CreateNSString(type);
    NSDictionary* nsMap = (__bridge NSDictionary*)map;
    
    [AlibabaCloudRUMSDK reportView:nsViewId
                          loadTime:loadTime
                             enter:enter
                              name:nsName
                            method:nsMethod
                               map:nsMap
                              type:nsType];
}

#pragma mark - Helper Functions for Object Creation

void* AlibabaCloudTraceContext_create(const char* traceId, const char* spanId, const char* parentSpanId,
                                       bool sampled, int protocol) {
    NSString* nsTraceId = CreateNSString(traceId);
    NSString* nsSpanId = CreateNSString(spanId);
    NSString* nsParentSpanId = CreateNSString(parentSpanId);
    
    AlibabaCloudTraceProtocol traceProtocol = (protocol == 0) ? AlibabaCloud_W3C : AlibabaCloud_SkywalkingV3;
    
    AlibabaCloudTraceContext* context;
    if (nsParentSpanId != nil && [nsParentSpanId length] > 0) {
        context = [AlibabaCloudTraceContext contextWithTraceId:nsTraceId
                                                        spanId:nsSpanId
                                                  parentSpanId:nsParentSpanId
                                                       sampled:sampled
                                                      protocol:traceProtocol];
    } else {
        context = [AlibabaCloudTraceContext contextWithTraceId:nsTraceId
                                                        spanId:nsSpanId
                                                      protocol:traceProtocol];
    }
    
    return (__bridge_retained void*)context;
}

void AlibabaCloudTraceContext_release(void* context) {
    if (context != NULL) {
        CFRelease(context);
    }
}

void* AlibabaCloudResourceMeasuring_create(unsigned long long duration, unsigned long long size,
                                            unsigned long long connectDuration, unsigned long long sslDuration,
                                            unsigned long long dnsDuration, unsigned long long redirectDuration,
                                            unsigned long long firstByteDuration, unsigned long long downloadDuration) {
    AlibabaCloudResourceMeasuring* measuring = [AlibabaCloudResourceMeasuring measuring];
    measuring.duration = (NSUInteger)duration;
    measuring.size = (NSUInteger)size;
    measuring.connectDuration = (NSUInteger)connectDuration;
    measuring.sslDuration = (NSUInteger)sslDuration;
    measuring.dnsDuration = (NSUInteger)dnsDuration;
    measuring.redirectDuration = (NSUInteger)redirectDuration;
    measuring.firstByteDuration = (NSUInteger)firstByteDuration;
    measuring.downloadDuration = (NSUInteger)downloadDuration;
    
    return (__bridge_retained void*)measuring;
}

void AlibabaCloudResourceMeasuring_release(void* measuring) {
    if (measuring != NULL) {
        CFRelease(measuring);
    }
}

void* NSDictionary_create(void) {
    NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
    return (__bridge_retained void*)dict;
}

void NSDictionary_addString(void* dict, const char* key, const char* value) {
    if (dict == NULL) {
        return;
    }
    
    NSMutableDictionary* nsDict = (__bridge NSMutableDictionary*)dict;
    NSString* nsKey = CreateNSString(key);
    NSString* nsValue = CreateNSString(value);
    
    if (nsKey != nil && nsValue != nil) {
        [nsDict setObject:nsValue forKey:nsKey];
    }
}

void NSDictionary_release(void* dict) {
    if (dict != NULL) {
        CFRelease(dict);
    }
}
