#import "DynamicClientScreenshotProtection.h"
#import <UIKit/UIKit.h>
#import <React/RCTBridgeModule.h>
#import <DynamicClientSpec/DynamicClientSpec.h>

@interface DynamicClientScreenshotProtection () <NativeScreenshotProtectionSpec> {
  // Screenshot/recording protection state (see setEnabled:). All three are only
  // touched on the main thread. `_secureField` doubles as the "are we currently
  // protecting?" guard so setEnabled:NO never tears down a state we did not set
  // up. `_originalWindowSuperlayer` is captured on enable so disable can restore
  // the window layer to exactly where it was reparented from.
  UITextField *_secureField;
  UIWindow *_secureWindow;
  CALayer *_originalWindowSuperlayer;
}
@end

@implementation DynamicClientScreenshotProtection

RCT_EXPORT_MODULE()

- (void)setEnabled:(BOOL)enabled {
  // iOS has no public equivalent of Android's FLAG_SECURE, so we use the
  // well-established "secure text entry canvas" technique: a UITextField with
  // secureTextEntry == YES owns a special render layer that the system excludes
  // from screenshots and screen recordings. By reparenting the key window's
  // layer underneath that secure canvas, the entire window renders blank in any
  // capture while staying fully visible on the physical screen. This relies on
  // the secure canvas being the text field layer's first sublayer — undocumented
  // but stable across iOS releases and free of private API symbols. Best-effort:
  // if the window/layer can't be resolved we silently skip rather than block the
  // calling flow.
  //
  // UIKit layer surgery must run on the main thread.
  dispatch_async(dispatch_get_main_queue(), ^{
    if (enabled) {
      // Already protecting — setEnabled:YES is idempotent.
      if (self->_secureField) {
        return;
      }
      UIWindow *window = [self dynamicKeyWindow];
      CALayer *originalSuperlayer = window.layer.superlayer;
      if (!window || !originalSuperlayer) {
        return;
      }
      UITextField *field = [[UITextField alloc] initWithFrame:window.bounds];
      field.secureTextEntry = YES;
      // Purely a protection shim — must never intercept touches.
      field.userInteractionEnabled = NO;
      [window addSubview:field];
      // The secure-entry "canvas" (the layer iOS excludes from screenshots/
      // recordings) is a private subview that UIKit does NOT create until the
      // field has been laid out inside a window. Force a layout pass first,
      // otherwise the lookup below finds nothing and protection silently no-ops.
      [field layoutIfNeeded];
      CALayer *secureLayer = [self secureCanvasLayerForField:field];
      if (!secureLayer) {
        // UIKit internals changed and the secure canvas couldn't be found — bail
        // without reparenting so the window is never left half-detached.
        [field removeFromSuperview];
        return;
      }
      // Move the window's layer underneath the secure canvas so the whole window
      // inherits the "not captured" property; keep the field's own layer as a
      // sibling under the original superlayer so the canvas stays in the tree.
      [originalSuperlayer addSublayer:field.layer];
      [secureLayer addSublayer:window.layer];
      self->_secureField = field;
      self->_secureWindow = window;
      self->_originalWindowSuperlayer = originalSuperlayer;
    } else {
      // Not protecting (or never were) — nothing to undo.
      if (!self->_secureField) {
        return;
      }
      // Move the window layer back out of the secure canvas to its original
      // parent, then drop our shim field entirely.
      [self->_originalWindowSuperlayer addSublayer:self->_secureWindow.layer];
      [self->_secureField.layer removeFromSuperlayer];
      [self->_secureField removeFromSuperview];
      self->_secureField = nil;
      self->_secureWindow = nil;
      self->_originalWindowSuperlayer = nil;
    }
  });
}

// Finds the secure-entry "canvas" layer of a secureTextEntry field — the layer
// iOS excludes from screenshots/recordings. Its position in the field's
// view/layer tree varies across iOS versions, so probe defensively: prefer a
// subview whose class name marks it as the canvas/content host, then fall back
// to the first sublayer of the field's own layer. Returns nil if neither is
// present (UIKit internals changed), so the caller can skip cleanly.
- (CALayer *)secureCanvasLayerForField:(UITextField *)field {
  for (UIView *subview in field.subviews) {
    NSString *className = NSStringFromClass(subview.class);
    if ([className containsString:@"Canvas"] ||
        [className containsString:@"Content"]) {
      return subview.layer;
    }
  }
  return field.layer.sublayers.firstObject;
}

// Resolves the foreground-active key window across connected scenes, falling
// back to the first window of any window scene. Used by setEnabled: to apply
// screenshot protection at the window level.
- (UIWindow *)dynamicKeyWindow {
  UIWindow *fallback = nil;
  for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
    if (![scene isKindOfClass:[UIWindowScene class]]) {
      continue;
    }
    UIWindowScene *windowScene = (UIWindowScene *)scene;
    for (UIWindow *window in windowScene.windows) {
      if (window.isKeyWindow) {
        return window;
      }
      if (!fallback) {
        fallback = window;
      }
    }
  }
  return fallback;
}

- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
    (const facebook::react::ObjCTurboModule::InitParams &)params {
  return std::make_shared<facebook::react::NativeScreenshotProtectionSpecJSI>(
      params);
}

+ (BOOL)requiresMainQueueSetup {
  return NO;
}

@end
