#import "RNSBarButtonItem.h"
#import <React/RCTConvert.h>
#import <React/RCTFont.h>
#import "RNSDefines.h"
#import "RNSImageLoadingHelper.h"

static UIMenuOptions RNSMakeUIMenuOptionsFromConfig(NSDictionary *config);

@implementation RNSBarButtonItem {
  NSString *_buttonId;
  RNSBarButtonItemAction _itemAction;
}

- (instancetype)initWithConfig:(NSDictionary<NSString *, id> *)dict
                        action:(RNSBarButtonItemAction)action
                    menuAction:(RNSBarButtonMenuItemAction)menuAction
                   imageLoader:(RCTImageLoader *)imageLoader
{
  self = [super init];
  if (!self) {
    return self;
  }

  [[self class] resolveImageFromConfig:dict
                           imageLoader:imageLoader
                       completionBlock:^(UIImage *img) {
                         self.image = img;
                       }];

  NSString *title = dict[@"title"];
  if (title != nil) {
    self.title = title;

    NSDictionary *titleStyle = dict[@"titleStyle"];
    if (titleStyle != nil) {
      [self setTitleStyleFromConfig:titleStyle];
    }
  }

  id tintColorObj = dict[@"tintColor"];
  if (tintColorObj) {
    self.tintColor = [RCTConvert UIColor:tintColorObj];
  }

#if !TARGET_OS_TV
  NSNumber *selectedNum = dict[@"selected"];
  if (selectedNum != nil) {
    self.selected = [selectedNum boolValue];
  }
#endif

  NSNumber *disabledNum = dict[@"disabled"];
  if (disabledNum != nil) {
    self.enabled = ![disabledNum boolValue];
  }

  NSNumber *width = dict[@"width"];
  if (width) {
    self.width = [width doubleValue];
  }

#if !TARGET_OS_TV || __TV_OS_VERSION_MAX_ALLOWED >= 170000
  if (@available(tvOS 17.0, *)) {
    NSNumber *changesSelectionAsPrimaryActionNum = dict[@"changesSelectionAsPrimaryAction"];
    if (changesSelectionAsPrimaryActionNum != nil) {
      self.changesSelectionAsPrimaryAction = [changesSelectionAsPrimaryActionNum boolValue];
    }
  }
#endif

#if RNS_IPHONE_OS_VERSION_AVAILABLE(26_0)
  if (@available(iOS 26.0, *)) {
    NSNumber *hidesSharedBackgroundNum = dict[@"hidesSharedBackground"];
    if (hidesSharedBackgroundNum != nil) {
      self.hidesSharedBackground = [hidesSharedBackgroundNum boolValue];
    }
    NSNumber *sharesBackgroundNum = dict[@"sharesBackground"];
    if (sharesBackgroundNum != nil) {
      self.sharesBackground = [sharesBackgroundNum boolValue];
    }
    NSString *identifier = dict[@"identifier"];
    if (identifier != nil) {
      self.identifier = identifier;
    }
    NSDictionary *badgeConfig = dict[@"badge"];
    if (badgeConfig != nil) {
      [self setBadgeFromConfig:badgeConfig];
    }
  }
#endif

  NSString *variant = dict[@"variant"];
  if (variant) {
    if ([variant isEqualToString:@"done"]) {
      self.style = UIBarButtonItemStyleDone;
    } else if ([variant isEqualToString:@"prominent"]) {
#if RNS_IPHONE_OS_VERSION_AVAILABLE(26_0)
      if (@available(iOS 26.0, *)) {
        self.style = UIBarButtonItemStyleProminent;
      }
#endif
    } else {
      self.style = UIBarButtonItemStylePlain;
    }
  }

  if (dict[@"accessibilityLabel"]) {
    self.accessibilityLabel = dict[@"accessibilityLabel"];
  }
  if (dict[@"accessibilityHint"]) {
    self.accessibilityHint = dict[@"accessibilityHint"];
  }

#if !TARGET_OS_TV || __TV_OS_VERSION_MAX_ALLOWED >= 170000
  if (@available(tvOS 17.0, *)) {
    NSDictionary *menu = dict[@"menu"];
    if (menu) {
      self.menu = [[self class] initUIMenuWithDict:menu menuAction:menuAction imageLoader:imageLoader];
    }
  }
#endif

  NSString *buttonId = dict[@"buttonId"];
  if (buttonId && action) {
    self.target = self;
    self.action = @selector(handleBarButtonItemPress:);
    _itemAction = action;
    _buttonId = buttonId;
  }
  return self;
}

+ (void)resolveImageFromConfig:(NSDictionary *)dict
                   imageLoader:(RCTImageLoader *)imageLoader
               completionBlock:(void (^)(UIImage *_Nullable))completionBlock
{
  NSString *sfSymbolName = dict[@"sfSymbolName"];
  if (sfSymbolName != nil) {
    completionBlock([UIImage systemImageNamed:sfSymbolName]);
    return;
  }

  NSString *xcassetName = dict[@"xcassetName"];
  if (xcassetName != nil) {
    completionBlock([UIImage imageNamed:xcassetName]);
    return;
  }

  NSDictionary *imageSourceObj = dict[@"imageSource"];
  NSDictionary *templateSourceObj = dict[@"templateSource"];
  if (imageSourceObj != nil || templateSourceObj != nil) {
    BOOL isTemplate = imageSourceObj == nil;
    NSDictionary *source = imageSourceObj != nil ? imageSourceObj : templateSourceObj;
    [RNSImageLoadingHelper loadImageSyncIfPossibleFromJsonSource:source
                                                 withImageLoader:imageLoader
                                                      asTemplate:isTemplate
                                                 completionBlock:completionBlock];
    return;
  }

  completionBlock(nil);
}

+ (UIMenu *)initUIMenuWithDict:(NSDictionary<NSString *, id> *)dict
                    menuAction:(RNSBarButtonMenuItemAction)menuAction
                   imageLoader:(RCTImageLoader *)imageLoader
{
  NSArray *items = dict[@"items"];
  NSMutableArray<UIMenuElement *> *elements = [NSMutableArray new];
  if (items.count > 0) {
    for (NSDictionary *item in items) {
      NSString *menuId = item[@"menuId"];
      if (menuId) {
        UIAction *actionItem = [self createActionItemFromConfig:item menuAction:menuAction imageLoader:imageLoader];
        [elements addObject:actionItem];
      } else {
        UIMenu *childMenu = [self initUIMenuWithDict:item menuAction:menuAction imageLoader:imageLoader];
        if (childMenu) {
          [elements addObject:childMenu];
        }
      }
    }
  }
  __block UIImage *image = nil;
  [self resolveImageFromConfig:dict
                   imageLoader:imageLoader
               completionBlock:^(UIImage *img) {
                 image = img;
               }];

  return [UIMenu menuWithTitle:dict[@"title"]
                         image:image
                    identifier:nil
                       options:RNSMakeUIMenuOptionsFromConfig(dict)
                      children:elements];
}

+ (UIAction *)createActionItemFromConfig:(NSDictionary *)dict
                              menuAction:(RNSBarButtonMenuItemAction)menuAction
                             imageLoader:(RCTImageLoader *)imageLoader
{
  NSString *menuId = dict[@"menuId"];

  UIAction *actionElement = [UIAction actionWithTitle:dict[@"title"]
                                                image:nil
                                           identifier:nil
                                              handler:^(__kindof UIAction *_Nonnull a) {
                                                menuAction(menuId);
                                              }];

  [self resolveImageFromConfig:dict
                   imageLoader:imageLoader
               completionBlock:^(UIImage *img) {
                 actionElement.image = img;
               }];

  NSString *discoverabilityLabel = dict[@"discoverabilityLabel"];
  if (discoverabilityLabel != nil) {
    actionElement.discoverabilityTitle = discoverabilityLabel;
  }

  NSString *state = dict[@"state"];
  if ([state isEqualToString:@"on"]) {
    actionElement.state = UIMenuElementStateOn;
  } else if ([state isEqualToString:@"off"]) {
    actionElement.state = UIMenuElementStateOff;
  } else if ([state isEqualToString:@"mixed"]) {
    actionElement.state = UIMenuElementStateMixed;
  }

  NSNumber *disabled = dict[@"disabled"];
  NSNumber *hidden = dict[@"hidden"];
  NSNumber *destructive = dict[@"destructive"];
  NSNumber *keepsMenuPresented = dict[@"keepsMenuPresented"];

  if (disabled != nil && [disabled boolValue]) {
    actionElement.attributes |= UIMenuElementAttributesDisabled;
  }

  if (hidden != nil && [hidden boolValue]) {
    actionElement.attributes |= UIMenuElementAttributesHidden;
  }

  if (destructive != nil && [destructive boolValue]) {
    actionElement.attributes |= UIMenuElementAttributesDestructive;
  }

  if (keepsMenuPresented != nil && [keepsMenuPresented boolValue]) {
#if RNS_IPHONE_OS_VERSION_AVAILABLE(16_0)
    if (@available(iOS 16.0, *)) {
      actionElement.attributes |= UIMenuElementAttributesKeepsMenuPresented;
    }
#endif
#if TARGET_OS_TV && __TV_OS_VERSION_MAX_ALLOWED >= 160000
    if (@available(tvOS 16.0, *)) {
      actionElement.attributes |= UIMenuElementAttributesKeepsMenuPresented;
    }
#endif
  }

  NSString *subtitle = dict[@"subtitle"];
  if (subtitle != nil) {
    actionElement.subtitle = subtitle;
  }

  return actionElement;
}

- (void)handleBarButtonItemPress:(UIBarButtonItem *)item
{
  if (_itemAction && _buttonId) {
    _itemAction(_buttonId);
  }
}

- (void)setTitleStyleFromConfig:(NSDictionary *)titleStyle
{
  NSString *fontFamily = titleStyle[@"fontFamily"];
  NSNumber *fontSize = titleStyle[@"fontSize"];
  NSString *fontWeight = titleStyle[@"fontWeight"];
  NSMutableDictionary *attrs = [NSMutableDictionary new];
  if (fontFamily || fontWeight) {
    NSNumber *resolvedFontSize = fontSize;
    if (!resolvedFontSize) {
#if TARGET_OS_TV
      resolvedFontSize = [NSNumber numberWithDouble:17.0];
#else
      resolvedFontSize = [NSNumber numberWithFloat:[UIFont labelFontSize]];
#endif
    }

    attrs[NSFontAttributeName] = [RCTFont updateFont:nil
                                          withFamily:fontFamily
                                                size:resolvedFontSize
                                              weight:fontWeight
                                               style:nil
                                             variant:nil
                                     scaleMultiplier:1.0];
  } else {
    CGFloat resolvedFontSize = fontSize ? [fontSize floatValue] : 0;
    if (resolvedFontSize == 0) {
#if TARGET_OS_TV
      resolvedFontSize = 17.0;
#else
      resolvedFontSize = [UIFont labelFontSize];
#endif
    }

    attrs[NSFontAttributeName] = [UIFont systemFontOfSize:resolvedFontSize];
  }
  id titleColor = titleStyle[@"color"];
  if (titleColor) {
    attrs[NSForegroundColorAttributeName] = [RCTConvert UIColor:titleColor];
  }
  [self setTitleTextAttributes:attrs forState:UIControlStateNormal];
  [self setTitleTextAttributes:attrs forState:UIControlStateHighlighted];
  [self setTitleTextAttributes:attrs forState:UIControlStateDisabled];
  [self setTitleTextAttributes:attrs forState:UIControlStateSelected];
  [self setTitleTextAttributes:attrs forState:UIControlStateFocused];
}

#if RNS_IPHONE_OS_VERSION_AVAILABLE(26_0)
- (void)setBadgeFromConfig:(NSDictionary *)badgeObj
{
  if (@available(iOS 26.0, *)) {
    UIBarButtonItemBadge *badge = [UIBarButtonItemBadge badgeWithString:badgeObj[@"value"]];
    NSDictionary *style = badgeObj[@"style"];
    if (style) {
      id colorObj = style[@"color"];
      if (colorObj) {
        badge.foregroundColor = [RCTConvert UIColor:colorObj];
      }
      id backgroundColorObj = style[@"backgroundColor"];
      if (backgroundColorObj) {
        badge.backgroundColor = [RCTConvert UIColor:backgroundColorObj];
      }
      NSString *fontFamily = style[@"fontFamily"];
      NSNumber *fontSize = style[@"fontSize"];
      NSString *fontWeight = style[@"fontWeight"];
      if (fontSize || fontWeight) {
        badge.font = [RCTFont updateFont:nil
                              withFamily:fontFamily
                                    size:fontSize
                                  weight:fontWeight
                                   style:nil
                                 variant:nil
                         scaleMultiplier:1.0];
      } else {
        CGFloat resolvedFontSize = fontSize ? [fontSize floatValue] : 0;
        if (resolvedFontSize == 0) {
#if TARGET_OS_TV
          resolvedFontSize = 17.0;
#else
          resolvedFontSize = [UIFont labelFontSize];
#endif
        }
        badge.font = [UIFont systemFontOfSize:resolvedFontSize];
      }
    }
    self.badge = badge;
  }
}
#endif

@end

UIMenuOptions RNSMakeUIMenuOptionsFromConfig(NSDictionary *config)
{
  UIMenuOptions options = 0;
  NSNumber *singleSelection = config[@"singleSelection"];
  NSNumber *displayAsPalette = config[@"displayAsPalette"];
  NSNumber *displayInline = config[@"displayInline"];
  NSNumber *destructive = config[@"destructive"];

  if (singleSelection != nil && [singleSelection boolValue]) {
    options |= UIMenuOptionsSingleSelection;
  }
#if RNS_IPHONE_OS_VERSION_AVAILABLE(17_0)
  if (@available(iOS 17.0, *)) {
    if (displayAsPalette != nil && [displayAsPalette boolValue]) {
      options |= UIMenuOptionsDisplayAsPalette;
    }
  }
#endif // RNS_IPHONE_OS_VERSION_AVAILABLE(17_0)
  if (displayInline != nil && [displayInline boolValue]) {
    options |= UIMenuOptionsDisplayInline;
  }
  if (destructive != nil && [destructive boolValue]) {
    options |= UIMenuOptionsDestructive;
  }
  return options;
}
