#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <SafariServices/SafariServices.h>
#import <WebKit/WebKit.h>
#import <React/RCTViewUtils.h>

#import "WebviewFabricView.h"

#import <react/renderer/components/FluentAdFlowWidgetSpec/ComponentDescriptors.h>
#import <react/renderer/components/FluentAdFlowWidgetSpec/EventEmitters.h>
#import <react/renderer/components/FluentAdFlowWidgetSpec/Props.h>
#import <react/renderer/components/FluentAdFlowWidgetSpec/RCTComponentViewHelpers.h>

#import "RCTFabricComponentsPlugins.h"
#import <FluentAdFlowAdsWidget/FluentAdFlowAdsWidget-Swift.h>
#import "ConvertDynamicToNSDictionary.h"

using namespace facebook::react;

@interface WebviewFabricView () <RCTWebviewFabricViewViewProtocol>
@end

@implementation WebviewFabricView {
  FluentAdFlowWidgetView *_view;
  EventManager *_eventManager;
  CGFloat _containerHeight;
}

+ (ComponentDescriptorProvider)componentDescriptorProvider {
  return concreteComponentDescriptorProvider<WebviewFabricViewComponentDescriptor>();
}

#pragma mark - Lifecycle

- (instancetype)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    _containerHeight = frame.size.height;
    [self initializeAdFlowViewIfNeededWithFrame:frame];
  }
  return self;
}

#pragma mark - Initialization Helper

- (void)initializeAdFlowViewIfNeededWithFrame:(CGRect)frame {
  if (_view != nil) {
    NSLog(@"[WebviewFabricView] Skipping initialization, _view already exists: %p", _view);
    return;
  }

  // Initialize Swift view
  _view = [[FluentAdFlowWidgetView alloc] initWithFrame:self.bounds];
  NSLog(@"[WebviewFabricView] init _view=%p frame=%@", _view, NSStringFromCGRect(frame));

  self.contentView = _view;
  _eventManager = _view.events;

  // Setup event listeners
  __weak WebviewFabricView *weakSelf = self;

  // Ad container closed
  [_eventManager listenToEventName:@"onAdFlowContainerClosed" action:^(id data, NSString *viewId) {
    __strong WebviewFabricView *strongSelf = weakSelf;
    if (!strongSelf || ![viewId isEqualToString:self->_view.viewId]) return;

    dispatch_async(dispatch_get_main_queue(), ^{
      self->_containerHeight = 0;
      [self updateContainerHeight];

      if (auto emitter = std::static_pointer_cast<const WebviewFabricViewEventEmitter>(self->_eventEmitter)) {
        WebviewFabricViewEventEmitter::OnAdShow event = {
          .shown = false,
          .viewId = [viewId UTF8String]
        };
        emitter->onAdShow(event);
      }
    });
  }];

  // Ad container shown
  [_eventManager listenToEventName:@"onAdFlowContainerShow" action:^(id data, NSString *viewId) {
    __strong WebviewFabricView *strongSelf = weakSelf;
    if (!strongSelf || ![viewId isEqualToString:self->_view.viewId]) return;

    dispatch_async(dispatch_get_main_queue(), ^{
      if (auto emitter = std::static_pointer_cast<const WebviewFabricViewEventEmitter>(self->_eventEmitter)) {
        WebviewFabricViewEventEmitter::OnAdShow event = {
          .shown = true,
          .viewId = [viewId UTF8String]
        };
        emitter->onAdShow(event);
      }
    });
  }];

  // Container height changed
  [_eventManager listenToEventName:@"onAdFlowContainerHeightChanged" action:^(id data, NSString *viewId) {
    __strong WebviewFabricView *strongSelf = weakSelf;
    if (!strongSelf || ![viewId isEqualToString:self->_view.viewId]) return;

    CGFloat newHeight = [data floatValue];
    dispatch_async(dispatch_get_main_queue(), ^{
      self->_containerHeight = newHeight;
      [self updateContainerHeight];

      if (auto emitter = std::static_pointer_cast<const WebviewFabricViewEventEmitter>(self->_eventEmitter)) {
        WebviewFabricViewEventEmitter::OnHeightChanged event = {
          .height = static_cast<int32_t>(newHeight),
          .viewId = [viewId UTF8String]
        };
        emitter->onHeightChanged(event);
      } else {
        NSLog(@"[WebviewFabricView] Fabric EventEmitter not available, cannot dispatch height change");
      }
    });
  }];

  // Internal ad closed
  [_eventManager listenToEventName:@"onInternalAdClosed" action:^(id data, NSString *viewId) {
    __strong WebviewFabricView *strongSelf = weakSelf;
    if (!strongSelf || ![viewId isEqualToString:self->_view.viewId]) return;

    dispatch_async(dispatch_get_main_queue(), ^{
      if (auto emitter = std::static_pointer_cast<const WebviewFabricViewEventEmitter>(self->_eventEmitter)) {
        WebviewFabricViewEventEmitter::OnInternalAdLaunched event = {
          .launched = false,
          .viewId = [viewId UTF8String]
        };
        emitter->onInternalAdLaunched(event);
      }
    });
  }];

  // Internal ad shown
  [_eventManager listenToEventName:@"onInternalAdShown" action:^(id data, NSString *viewId) {
    __strong WebviewFabricView *strongSelf = weakSelf;
    if (!strongSelf || ![viewId isEqualToString:self->_view.viewId]) return;

    dispatch_async(dispatch_get_main_queue(), ^{
      if (auto emitter = std::static_pointer_cast<const WebviewFabricViewEventEmitter>(self->_eventEmitter)) {
        WebviewFabricViewEventEmitter::OnInternalAdLaunched event = {
          .launched = true,
          .viewId = [viewId UTF8String]
        };
        emitter->onInternalAdLaunched(event);
      }
    });
  }];
}

#pragma mark - Layout Handling

- (void)updateContainerHeight {
  CGRect frame = self.frame;
  frame.size.height = _containerHeight;
  self.frame = frame;

  [self invalidateIntrinsicContentSize];
  [self setNeedsLayout];
}

#pragma mark - Props Update

- (void)updateProps:(facebook::react::Props::Shared const &)props
           oldProps:(facebook::react::Props::Shared const &)oldProps {
  const auto &newViewProps = *std::static_pointer_cast<const WebviewFabricViewProps>(props);

  // Ensure _view exists
  if (!_view) {
    NSLog(@"[WebviewFabricView] _view is nil in updateProps, recreating...");
    [self initializeAdFlowViewIfNeededWithFrame:self.bounds];
  }

  if (_view) {
    _view.isScrollingEnabled = newViewProps.isScrollingEnabled;

    if (!newViewProps.viewId.empty()) {
      _view.viewId = [NSString stringWithUTF8String:newViewProps.viewId.c_str()];
    }

    if (!newViewProps.wrapperName.empty()) {
      _view.wrapperName = [NSString stringWithUTF8String:newViewProps.wrapperName.c_str()];
    }

    if (!newViewProps.wrapperVersion.empty()) {
      _view.wrapperVersion = [NSString stringWithUTF8String:newViewProps.wrapperVersion.c_str()];
    }
  } else {
    NSLog(@"[WebviewFabricView] ERROR: _view is still nil after recreation attempt");
  }

  [super updateProps:props oldProps:oldProps];
}

#pragma mark - Commands

- (void)handleCommand:(NSString *)commandName args:(NSArray *)args {
  if ([commandName isEqualToString:@"setParams"]) {
    NSDictionary *params = @{};
    
    if (args.count > 0) {
      id arg = args[0];

      if ([arg isKindOfClass:[NSString class]]) {
        NSData *data = [(NSString *)arg dataUsingEncoding:NSUTF8StringEncoding];
        NSError *error = nil;
        id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

        if (!error && [jsonObject isKindOfClass:[NSDictionary class]]) {
          params = jsonObject;
        } else {
          NSLog(@"❌ JSON parse error in handleCommand:setParams: %@", error);
        }
      } else if ([arg isKindOfClass:[NSDictionary class]]) {
        params = (NSDictionary *)arg;
      }
    }

    dispatch_async(dispatch_get_main_queue(), ^{
      if (self->_view) {
        [self->_view setParams:params];
      } else {
        NSLog(@"[WebviewFabricView] setParams ignored because _view is nil");
      }
    });
  }
}

#pragma mark - View Lifecycle

- (void)didMoveToSuperview {
  [super didMoveToSuperview];
  if (!self.superview) {
    dispatch_async(dispatch_get_main_queue(), ^{
      self->_containerHeight = 0;
      [self updateContainerHeight];
    });
  }
}

- (void)removeFromSuperview {
  NSLog(@"[WebviewFabricView] removeFromSuperview called, clearing _view=%p", _view);
  
  if (_view) {
    [_view removeFromSuperview];
    _view = nil;
  }
  
  _eventManager = nil;
  [super removeFromSuperview];
}

- (BOOL)prepareForReuse {
  NSLog(@"[WebviewFabricView] prepareForReuse CALLED on _view=%p", _view);
  
  if (_view) {
    [_view removeFromSuperview];
    _view = nil;
  }
  
  _eventManager = nil;
  
  return NO; // force Fabric to allocate a new instance
}

@end
