// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterKeyboardManager.h"
#include "flutter/fml/memory/weak_ptr.h"
#include "flutter/fml/platform/darwin/message_loop_darwin.h"

static constexpr CFTimeInterval kDistantFuture = 1.0e10;

@interface FlutterKeyboardManager ()

/**
 * The primary responders added by addPrimaryResponder.
 */
@property(nonatomic) NSMutableArray<id<FlutterKeyPrimaryResponder>>* primaryResponders;

/**
 * The secondary responders added by addSecondaryResponder.
 */
@property(nonatomic) NSMutableArray<id<FlutterKeySecondaryResponder>>* secondaryResponders;

- (void)dispatchToSecondaryResponders:(nonnull FlutterUIPressProxy*)press
                             complete:(nonnull KeyEventCompleteCallback)callback
    API_AVAILABLE(ios(13.4));

@end

@implementation FlutterKeyboardManager {
  std::unique_ptr<fml::WeakPtrFactory<FlutterKeyboardManager>> _weakFactory;
}

- (nonnull instancetype)init {
  self = [super init];
  if (self != nil) {
    _primaryResponders = [[NSMutableArray alloc] init];
    _secondaryResponders = [[NSMutableArray alloc] init];
    _weakFactory = std::make_unique<fml::WeakPtrFactory<FlutterKeyboardManager>>(self);
  }
  return self;
}

- (void)addPrimaryResponder:(nonnull id<FlutterKeyPrimaryResponder>)responder {
  [_primaryResponders addObject:responder];
}

- (void)addSecondaryResponder:(nonnull id<FlutterKeySecondaryResponder>)responder {
  [_secondaryResponders addObject:responder];
}

- (void)dealloc {
  [_primaryResponders removeAllObjects];
  [_secondaryResponders removeAllObjects];
  [_primaryResponders release];
  [_secondaryResponders release];
  _primaryResponders = nil;
  _secondaryResponders = nil;
  [super dealloc];
}

- (fml::WeakPtr<FlutterKeyboardManager>)getWeakPtr {
  return _weakFactory->GetWeakPtr();
}

- (void)handlePress:(nonnull FlutterUIPressProxy*)press
         nextAction:(nonnull void (^)())next API_AVAILABLE(ios(13.4)) {
  if (@available(iOS 13.4, *)) {
    // no-op
  } else {
    return;
  }

  bool __block wasHandled = false;
  KeyEventCompleteCallback completeCallback = ^void(bool handled, FlutterUIPressProxy* press) {
    wasHandled = handled;
    CFRunLoopStop(CFRunLoopGetCurrent());
  };
  switch (press.phase) {
    case UIPressPhaseBegan:
    case UIPressPhaseEnded: {
      // Having no primary responders requires extra logic, but Flutter hard-codes
      // all primary responders, so this is a situation that Flutter will never
      // encounter.
      NSAssert([_primaryResponders count] >= 0, @"At least one primary responder must be added.");

      __block auto weakSelf = [self getWeakPtr];
      __block int unreplied = [_primaryResponders count];
      __block BOOL anyHandled = false;
      FlutterAsyncKeyCallback replyCallback = ^(BOOL handled) {
        unreplied--;
        NSAssert(unreplied >= 0, @"More primary responders replied than expected.");
        anyHandled = anyHandled || handled;
        if (unreplied == 0) {
          if (!anyHandled && weakSelf) {
            [weakSelf.get() dispatchToSecondaryResponders:press complete:completeCallback];
          } else {
            completeCallback(true, press);
          }
        }
      };
      for (id<FlutterKeyPrimaryResponder> responder in _primaryResponders) {
        [responder handlePress:press callback:replyCallback];
      }
      // Create a nested run loop while we wait for a response from the
      // framework. Once the completeCallback is called, this run loop will exit
      // and the main one will resume. The completeCallback MUST be called, or
      // the app will get stuck in this run loop indefinitely.
      //
      // We need to run in this mode so that UIKit doesn't give us new
      // events until we are done processing this one.
      CFRunLoopRunInMode(fml::MessageLoopDarwin::kMessageLoopCFRunLoopMode, kDistantFuture, NO);
      break;
    }
    case UIPressPhaseChanged:
    case UIPressPhaseCancelled:
    case UIPressPhaseStationary:
      break;
  }
  if (!wasHandled) {
    next();
  }
}

#pragma mark - Private

- (void)dispatchToSecondaryResponders:(nonnull FlutterUIPressProxy*)press
                             complete:(nonnull KeyEventCompleteCallback)callback
    API_AVAILABLE(ios(13.4)) {
  if (@available(iOS 13.4, *)) {
    // no-op
  } else {
    callback(false, press);
    return;
  }

  for (id<FlutterKeySecondaryResponder> responder in _secondaryResponders) {
    if ([responder handlePress:press]) {
      callback(true, press);
      return;
    }
  }
  callback(false, press);
}

@end
