//
//  AAILivenessWrapView.h
//  AAILivenessSDK
//
//  Created by Advance.ai on 2019/3/1.
//  Copyright © 2019 Advance.ai. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <AAILivenessSDK/AAIDetectionConstant.h>
#import <AAILivenessSDK/AAILivenessResult.h>
#import <AAILivenessSDK/AAILivenessSuccessResult.h>
#import <AAILivenessSDK/AAILivenessFailureResult.h>
#import <AAILivenessSDK/AAIEllipseTrasitionContext.h>
#import <AAILivenessSDK/AAIOrientationTransitionContext.h>
#import <AAILivenessSDK/AAIDetectionResultContext.h>
#import <AAILivenessSDK/AAILivenessFrame.h>
#import <AAILivenessSDK/AAILivenessConfig.h>

@class AAILivenessWrapView;
@protocol AAILivenessWrapDelegate <NSObject>

@optional

/**
 This method will be called before the detection starts.
 
 @since 3.4.0
 */
- (void)onBeforeStartDetection;

/**
 This method will be called whenever a new video frame is received.
 
 @note This method is called on camera queue. When implementing this method, avoid performing time-consuming operations,
 as this can negatively impact the liveness detection logic.
 
 @since 3.4.0
 */
- (void)onOriginalFrameReceived:(AAILivenessFrame * _Nonnull)frame;

/**
 This method will be called when detection result is changed. It's called on the main thread.

 @param resultContext Detection result context.
 @since 4.0.0
 */
- (void)onDetectionResultChanged:(AAIDetectionResultContext * _Nonnull)resultContext;

/**
 This method will be called when liveness stage changed. It's called on the main thread.
 
 @note When the livenessStage is AAILivenessStageDetectionSuccess, it indicates that liveness detection has succeeded and the SDK
 will begin uploading data. If the data upload succeeds, the method `onFinalDetectionSuccess:` will be called;
 otherwise, the method `onFinalDetectionFailure:` will be called.

 @param newLivenessStage The new liveness stage.
 @since 4.0.0
 */
- (void)onLivenessStageChanged:(AAILivenessStage)newLivenessStage;

/**
 The remaining detection time of the specific liveness stage has changed, this method is called about once per second.

 @param remainingTime The remaining time, in seconds.
 @param livenessStage The specific liveness stage.
 @since 4.0.0
 */
- (void)onDetectionRemainingTimeChanged:(NSInteger)remainingTime forLivenessStage:(AAILivenessStage)livenessStage;

/**
 Send before loading a request.

 @param param wrap view
 @since 1.0.0
 */
- (void)livenessViewBeginRequest:(AAILivenessWrapView * _Nonnull)param;

/**
 Sent after a wrap view finishes loading a request.

 @param param wrap view
 @param error An error object indicating load a request failed
 @since 1.0.0
 */
- (void)livenessView:(AAILivenessWrapView * _Nonnull)param endRequest:(NSError * _Nullable)error;

/**
 @since 3.1.0
 */
- (void)livenessView:(AAILivenessWrapView * _Nonnull)param ellipseWillTransition:(AAIEllipseTrasitionContext * _Nonnull)context;

/**
 Send after detection success. It's called on the main thread.

 @param successResult A AAILivenessSuccessResult object contain 'livenessId' NSString object and 'img' UIImage object.
 @since 4.0.0
 */
- (void)onFinalDetectionSuccess:(AAILivenessSuccessResult * _Nonnull)successResult;

/**
 Send after detection failure. It's called on the main thread.

 @param failureResult A AAILivenessFailureResult object contains detail error informations.
 @since 4.0.0
 */
- (void)onFinalDetectionFailure:(AAILivenessFailureResult * _Nonnull)failureResult;


/*===================================================================+
 |                            !!!WARNING                             |
 |NOTE THE FOLLOWING DELEGATE METHODS NO LONGER AVAILABLE FROM V4.0.0|
 +===================================================================*/

/**
 This method will be called when opening the camera fails.
 @since 3.0.5
 */
- (void)onOpenCameraFailed:(NSError * _Nonnull)error AAI_LD_UNAVAILABLE_FROM(4.0.0, "Using `onFinalDetectionFailure:` instead");

/**
 This method will be called when the detection fails. Note that the detector will be stopped if the detection fails.

 @param detectionResult Detection result.
 @param detectionType Current detection type.
 @since 1.0.0
 */
- (void)onDetectionFailed:(AAIDetectionResult)detectionResult forDetectionType:(AAIDetectionType)detectionType AAI_LD_UNAVAILABLE_FROM(4.0.0, "Using `onFinalDetectionFailure:` instead");

/**
 This method will be called whenever a new video frame is detected.

 @param result Detection result.
 @param status Action status.
 @param detectionType Current detection type.
 @since 1.0.0
 */
- (void)onFrameDetected:(AAIDetectionResult)result status:(AAIActionStatus)status forDetectionType:(AAIDetectionType)detectionType AAI_LD_UNAVAILABLE_FROM(4.0.0);

/**
 This method will be called when the detection is ready.

 @param detectionType The first `AAIDetectionType` value in property `detectionActions`.
 @since 1.0.0
 */
- (void)onDetectionReady:(AAIDetectionType)detectionType AAI_LD_UNAVAILABLE_FROM(4.0.0);

/**
 This method will be called when detection type changed.

 @param toDetectionType The new detection type.
 @since 1.0.0
 */
- (void)onDetectionTypeChanged:(AAIDetectionType)toDetectionType AAI_LD_UNAVAILABLE_FROM(4.0.0, "Using `onLivenessStageChanged:` instead");

/**
 The remaing detection time of the current detection type, this method is called about once per second.

 @param remainingTime The remaining time, in seconds.
 @param detectionType Current detection type.
 @since 1.0.0
 */
- (void)onDetectionRemainingTime:(NSTimeInterval)remainingTime forDetectionType:(AAIDetectionType)detectionType AAI_LD_UNAVAILABLE_FROM(4.0.0, "Using `onDetectionRemainingTimeChanged:forLivenessStage:`");

/**
 This method is called after a successful detection, but before 'onDetectionComplete' is called.
 */
- (void)onDetectionSuccess AAI_LD_UNAVAILABLE_FROM(4.0.0, "Using `onLivenessStageChanged:` to check if detection success");

/**
 Send after detection complete.

 @param resultInfo A AAILivenessResult object contain 'livenessId' NSString object and 'img' UIImage object.
 @since 1.2.0
 */
- (void)onDetectionComplete:(AAILivenessResult * _Nonnull)resultInfo AAI_LD_UNAVAILABLE_FROM(4.0.0, "Using `onFinalDetectionSuccess:` instead");

@end


NS_ASSUME_NONNULL_BEGIN

__attribute__((visibility("default")))
@interface AAILivenessWrapView : UIView

/**
 @since 1.0.0
 */
@property(nonatomic, readonly) UIView *roundBorderView;

/**
 You can customize the width of the avatar preview area by implementing this method. Note that the avatar area is always square and horizontally centered.
  
 @code
 // Usage:
 wrapView.configAvatarPreviewWidth = ^CGFloat(CGRect wrapViewFrame) {
     return 300;
 };
 @endcode
 
 @since 1.1.4
 */
@property(nonatomic, copy, nullable) CGFloat (^configAvatarPreviewWidth)(CGRect wrapViewFrame);

/**
 You can customize the margin-top of the avatar preview area by implementing this method.
 
 @code
 // Usage:
 wrapView.configAvatarPreviewMarginTop = ^CGFloat(CGRect wrapViewFrame) {
     return 64;
 };
 @endcode
 
 @since 1.1.4
 */
@property(nonatomic, copy, nullable) CGFloat (^configAvatarPreviewMarginTop)(CGRect wrapViewFrame);

/**
 @since 1.0.0
 */
@property(nonatomic, weak, nullable) id<AAILivenessWrapDelegate> wrapDelegate;

/**
 The avatar preview area. Model only detecting faces in this area.
 @warning This is a experimental property and may not stable
 @since 1.2.3
 */
@property(nonatomic, assign) CGRect currAvatarPreviewArea;

/**
 The camera preview frame.
 
 @note If you configured this property, then the property `configAvatarPreviewMarginTop` and `configAvatarPreviewPath` will be ignored.
 @warning This is a experimental property and may not stable
 @since 1.2.3
 */
@property(nonatomic, assign) CGRect currPreviewFrame;

/**
 Start the liveness detection.
 
 @since 4.0.0
 */
- (void)startRunningWithConfig:(AAILivenessConfig *)livenessConfig;

/**
 Stop the liveness detection.
 
 @since 4.0.0
 */
- (void)stopRunning;

/**
 Auto stop the liveness detection and release resources if needed. This method is generally called when you no longer
 need the liveness detection, such as when the view controller is dealloc.
 
 @since 4.0.0
 */
- (void)releaseResources;

/**
 @since 3.0.0
 */
- (void)resetUI;

/**
 @since 3.1.0
 */
- (NSString *)latestEventId;

/**
 @since 4.0.0
 */
- (void)orientationWillTransition:(id<AAIOrientationTransitionContext>)transitionContext;

@end


/*=========================================================================+
 |                               !!!WARNING                                |
 |NOTE THE FOLLOWING PROPERTIES AND METHODS NO LONGER AVAILABLE FROM V4.0.0|
 +=========================================================================*/

@interface AAILivenessWrapView(DeprecatedOrUnavailable)

/**
 The list of detection actions, reference to AAIDetectionType, note that the `AAIDetectionTypeNone` will be ignored in this array.
 By default, the order of the first two actions is random, and the last action is fixed AAIDetectionTypePosYaw.
 
 @since 1.0.0
 */
@property(nonatomic, copy) NSArray<NSNumber *> *detectionActions AAI_LD_UNAVAILABLE_FROM(4.0.0);

/**
 Check camera's permission, if user grant, this method will start camera immediately.

 @param completionBlk A block to be called once permission is denied, and the value of "authed" is always NO. It's called on main thread.
 @since 1.0.0
 */
- (void)checkCameraPermissionWithCompletionBlk:(void (^_Nullable)(BOOL authed))completionBlk AAI_LD_UNAVAILABLE_FROM(4.0.0);

/**
 This propety is unavailable, please use configAvatarPreviewPathV2 instead.
 
 @since 1.1.3
 */
@property(nonatomic, copy, nullable) void (^configAvatarPreviewPath)(CGSize avatarPreviewSize, UIBezierPath *originRectPath) AAI_LD_UNAVAILABLE_FROM(2.0.1, "Using `configAvatarPreviewPathV2` instead");

/**
 You can customize the shape of the avatar preview area by implementing this method, the default avatar preview area is circular.
 "reactPath" represents the visible camera preview area, by configuring this value to customize the shape of the avatar preview area.
 
 @code
 // Set a square preview area
 wrapView.configAvatarPreviewPathV2 = ^(CGRect avatarPreviewFrame, UIBezierPath *originRectPath, AAILivenessWrapView *originWrapView) {
     UIBezierPath *squarePath = [UIBezierPath bezierPathWithRoundedRect:avatarPreviewFrame cornerRadius:0];
     [originRectPath appendPath: [squarePath bezierPathByReversingPath]];
 };
 
 // Set a circular preview area
 wrapView.configAvatarPreviewPathV2 = ^(CGRect avatarPreviewFrame, UIBezierPath * _Nonnull originRectPath, AAILivenessWrapView * _Nonnull originWrapView) {
     UIBezierPath *circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMidX(avatarPreviewFrame), CGRectGetMidY(avatarPreviewFrame)) radius:avatarPreviewFrame.size.width/2 startAngle:0 endAngle:M_PI * 2 clockwise:NO];
     [originRectPath appendPath:circlePath];
 };
 @endcode
 
 @since 2.0.1
 */
@property(nonatomic, copy, nullable) void (^configAvatarPreviewPathV2)(CGRect avatarPreviewFrame, UIBezierPath *originRectPath, AAILivenessWrapView *originWrapView) AAI_LD_DEPRECATED_FROM(3.0.0, "This property no longer supported and will have no effect even after calling");

/**
 @since 3.0.3
 */
@property(nonatomic, nullable) UIColor *ellipseLayerFillColor AAI_LD_UNAVAILABLE_FROM(4.1.0);

/**
 Send auth request.

 @param completionBlk A block to be called when auth request complete. It's called on main thread.
 @since 1.2.3
 */
- (void)startAuthWithCompletionBlk:(void (^_Nullable)(NSError * _Nullable error))completionBlk AAI_LD_UNAVAILABLE_FROM(4.0.0);

/**
 Stop the camera.
 
 @param reason Reasons why the camera was stopped. Currently available values are "prepare_timeout", "user_give_up".
 @since 2.0.7
 */
- (void)stopRunningWithReason:(NSString *)reason AAI_LD_UNAVAILABLE_FROM(4.0.0, "Using `stopRunning` instead");

@end

NS_ASSUME_NONNULL_END
