// LayersSKANCompat.m
#import "LayersSKANCompat.h"
#import <objc/message.h>
#include <dlfcn.h>

@implementation LayersSKANCompat

static NSString *_Nullable LayersGetNSStringConstant(const char *symbolName) {
  if (symbolName == NULL) return nil;
  void *addr = dlsym(RTLD_DEFAULT, symbolName);
  if (!addr) {
    // Try with leading underscore fallback
    char underscored[256];
    size_t n = strlen(symbolName);
    if (n + 2 < sizeof(underscored)) {
      underscored[0] = '_';
      memcpy(&underscored[1], symbolName, n);
      underscored[n + 1] = '\0';
      addr = dlsym(RTLD_DEFAULT, underscored);
    }
  }
  if (!addr) return nil;
  // NSString * const symbol => dlsym returns address of the pointer variable
  return *((NSString * const *)addr);
}

static NSString *_Nullable LayersCoarseConstantForString(NSString *_Nullable coarseString) {
  if (coarseString == nil) return nil;
  NSString *key = [[coarseString lowercaseString] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
  const char *symbol = NULL;
  if ([key isEqualToString:@"high"]) {
    symbol = "SKAdNetworkCoarseConversionValueHigh";
  } else if ([key isEqualToString:@"medium"]) {
    symbol = "SKAdNetworkCoarseConversionValueMedium";
  } else if ([key isEqualToString:@"low"]) {
    symbol = "SKAdNetworkCoarseConversionValueLow";
  }
  if (symbol) {
    NSString *constant = LayersGetNSStringConstant(symbol);
    if (constant) return constant;
  }
  // Fallback: pass through the provided string (SK_TYPED_ENUM is NSString *)
  return coarseString;
}

+ (void)updateConversionValue:(NSInteger)value
                   completion:(void (^ _Nullable)(NSError * _Nullable error))completion {
  Class cls = NSClassFromString(@"SKAdNetwork");
  if (!cls) { if (completion) completion(nil); return; }

  SEL selPostback15 = NSSelectorFromString(@"updatePostbackConversionValue:completionHandler:");
  if ([cls respondsToSelector:selPostback15]) {
    // void +[SKAdNetwork updatePostbackConversionValue:(NSInteger)cv completionHandler:(void (^)(NSError * error))completion]
    void (*msgSend)(id, SEL, NSInteger, void(^)(NSError *)) = (void *)objc_msgSend;
    msgSend(cls, selPostback15, value, ^(NSError *error){ if (completion) completion(error); });
    return;
  }

  SEL selLegacy = NSSelectorFromString(@"updateConversionValue:");
  if ([cls respondsToSelector:selLegacy]) {
    void (*msgSendLegacy)(id, SEL, NSInteger) = (void *)objc_msgSend;
    msgSendLegacy(cls, selLegacy, value);
    if (completion) completion(nil);
    return;
  }

  if (completion) completion(nil);
}

+ (void)updatePostbackConversionValue:(NSInteger)fineValue
                         coarseString:(NSString * _Nullable)coarseString
                            lockWindow:(BOOL)lockWindow
                             completion:(void (^ _Nullable)(NSError * _Nullable error))completion {
  Class cls = NSClassFromString(@"SKAdNetwork");
  if (!cls) { if (completion) completion(nil); return; }

  NSString *coarseArg = LayersCoarseConstantForString(coarseString);

  if (coarseArg != nil) {
    // iOS 16.1+ with lockWindow
    SEL sel161Lock = NSSelectorFromString(@"updatePostbackConversionValue:coarseValue:lockWindow:completionHandler:");
    if ([cls respondsToSelector:sel161Lock]) {
      void (*msgSend)(id, SEL, NSInteger, NSString * _Nullable, BOOL, void(^)(NSError *)) = (void *)objc_msgSend;
      msgSend(cls, sel161Lock, fineValue, coarseArg, lockWindow, ^(NSError *error){ if (completion) completion(error); });
      return;
    }

    // iOS 16.1+ (fine + coarse)
    SEL sel161 = NSSelectorFromString(@"updatePostbackConversionValue:coarseValue:completionHandler:");
    if ([cls respondsToSelector:sel161]) {
      void (*msgSend2)(id, SEL, NSInteger, NSString * _Nullable, void(^)(NSError *)) = (void *)objc_msgSend;
      msgSend2(cls, sel161, fineValue, coarseArg, ^(NSError *error){ if (completion) completion(error); });
      return;
    }
    // Fall through to fine-only if 16.1 coarse variants are unavailable
  }

  // iOS 15.4+ (fine only)
  SEL sel154 = NSSelectorFromString(@"updatePostbackConversionValue:completionHandler:");
  if ([cls respondsToSelector:sel154]) {
    void (*msgSend3)(id, SEL, NSInteger, void(^)(NSError *)) = (void *)objc_msgSend;
    msgSend3(cls, sel154, fineValue, ^(NSError *error){ if (completion) completion(error); });
    return;
  }

  // Fallback to legacy (iOS 14+)
  SEL selLegacy = NSSelectorFromString(@"updateConversionValue:");
  if ([cls respondsToSelector:selLegacy]) {
    void (*msgSendLegacy)(id, SEL, NSInteger) = (void *)objc_msgSend;
    msgSendLegacy(cls, selLegacy, fineValue);
    if (completion) completion(nil);
    return;
  }

  if (completion) completion(nil);
}

@end
