//
//  MVMCoreUITopAlertView.m
//  myverizon
//
//  Created by Chris Yang on 2/3/16.
//  Copyright © 2016 Verizon Wireless. All rights reserved.
//

#import "MVMCoreUITopAlertView.h"
#import "MVMCoreUICommonViewsUtility.h"
#import "UIColor+MFConvenience.h"
#import "MVMCoreUITopAlertShortView.h"
#import "MVMCoreUITopAlertMainView.h"
#import "MVMCoreUITopAlertExpandableView.h"
#import "MVMCoreUISplitViewController.h"
#import "NSLayoutConstraint+MFConvenience.h"
#import "MVMCoreUISession.h"
#import "MVMCoreUIUtility.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>
#import <MVMCoreUI/MVMCoreTopAlertObject.h>
@import MVMCore.MVMCoreLoadHandler;
@import MVMCore.MVMCoreNavigationHandler;
@import MVMCore.MVMCoreBlockOperation;
#import <MVMCoreUI/MVMCoreAlertObject.h>
@import MVMCore.MVMCoreActionHandler;
#import <MVMCoreUI/MVMCoreAlertHandler.h>
@import MVMCore.NSDictionary_MFConvenience;
@import MVMCore.MVMCoreRequestParameters;
@import MVMCore.MVMCoreJSONConstants;
@import MVMCore.MVMCoreDispatchUtility;

NSString * const MFAccTopAlertClosed = @"Top alert notification is closed.";

@interface MVMCoreUITopAlertView ()

@property (nonatomic, readwrite) UIStatusBarStyle statusBarStyle;
@property (weak, nonatomic) UIView *statusBarView;
@property (strong, nonatomic) NSLayoutConstraint *statusBarHeightConstraint;
@property (strong, nonatomic) NSLayoutConstraint *statusBarBottomConstraint;

@property (weak, nonatomic) UIView *alertView;
@property (weak, nullable, nonatomic, readwrite) UIView *currentAlert;
@property (strong, nonatomic) NSLayoutConstraint *height;

@property (weak, nonatomic) MVMCoreUITopAlertExpandableView *topAlertClearspotView;
@property (strong, nonatomic) NSString *time;

/// Used if we delayed the collapse due to accessibility.
@property (copy, nonatomic) void (^ hideCompletionHandler)(BOOL finished);

@end

@implementation MVMCoreUITopAlertView

- (instancetype)init {
    self = [super init];
    if (self) {
        [self setupView];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self setupView];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        [self setupView];
    }
    return self;
}

+ (nullable instancetype)sharedGlobal {
    return [MVMCoreUISession sharedGlobal].topAlertView;
}

+ (nullable instancetype)setupTopAlertView {
    MVMCoreUITopAlertView *topAlertView = [[self alloc] init];
    topAlertView.translatesAutoresizingMaskIntoConstraints = NO;
    [MVMCoreUISession sharedGlobal].topAlertView = topAlertView;
    return topAlertView;
}

- (void)setupView {
    if (!self.statusBarView) {
        self.clipsToBounds = YES;
        
        UIView *statusBarView = [MVMCoreUICommonViewsUtility commonView];
        UIView *alertView = [MVMCoreUICommonViewsUtility commonView];
        [self addSubview:alertView];
        [self addSubview:statusBarView];
        [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[statusBarView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(statusBarView)]];
        [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-0-[alertView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(alertView)]];
        [NSLayoutConstraint activateConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[statusBarView]-0-[alertView]-0-|" options:NSLayoutFormatDirectionLeadingToTrailing metrics:nil views:NSDictionaryOfVariableBindings(statusBarView,alertView)]];
        self.statusBarHeightConstraint = [statusBarView.heightAnchor constraintEqualToConstant:0];
        self.statusBarHeightConstraint.active = YES;
        self.height = [alertView.heightAnchor constraintEqualToConstant:0];
        self.height.active = YES;
        self.alertView = alertView;
        self.statusBarView = statusBarView;
        
        [self setStatusBarColor:[UIColor whiteColor] statusBarStyle:UIStatusBarStyleDefault];
        
        [self registerWithNotificationCenter];
    }
}

- (void)pinATopViewController:(UIViewController *)viewController {
    self.statusBarHeightConstraint.active = NO;
    id topGuide = viewController.view.safeAreaLayoutGuide;
    self.statusBarBottomConstraint = [NSLayoutConstraint constraintWithItem:self.statusBarView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:topGuide attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
    self.statusBarBottomConstraint.active = YES;
}

- (void)updateView:(CGFloat)size {
    if ([self.currentAlert respondsToSelector:@selector(updateView:)]) {
        [((UIView <MVMCoreViewProtocol>*)(self.currentAlert)) updateView:size];
    }
}

- (nonnull UIView *)topAlertViewForTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate statusBarColor:(UIColor *_Nullable *_Nullable)statusBarColor statusBarStyle:(UIStatusBarStyle *_Nullable)statusBarStyle {
    if (topAlertObject.json) {
        return [self moleculeFor:topAlertObject statusBarColor:statusBarColor statusBarStyle:statusBarStyle];
    } else {
        MVMCoreUITopAlertExpandableView *view = [[MVMCoreUITopAlertExpandableView alloc] initWithTopAlertObject:topAlertObject animationDelegate:animationDelegate viewToLayout:self.superview];
        if (statusBarColor && view.shortView.label.text) {
            *statusBarColor = view.backgroundColor;
            
            if (statusBarStyle) {
                CGFloat greyScale = 0;
                if ([view.shortView.label.textColor getWhite:&greyScale alpha:nil]) {
                    *statusBarStyle = greyScale > 0.5 ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault;
                }
            }
        }
        return view;
    }
}

- (nonnull UIColor *)getBackgroundColorForType:(nullable NSString *)type {
    if ([type isEqualToString:ValueTypeError]) {
        return [UIColor mvmOrange];
    } else {
        return [UIColor mvmGreen];
    }
}

- (nonnull UIColor *)getContentColorForType:(nullable NSString *)type {
    if ([type isEqualToString:ValueTypeError]) {
        return [UIColor blackColor];
    } else {
        return [UIColor whiteColor];
    }
}

- (void)showWithTopAlertObject:(nullable MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nonnull id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
    
    self.animationDelegate = animationDelegate;
    dispatch_async(dispatch_get_main_queue(), ^{
        
        self.topAlertObject = topAlertObject;
        self.topAlertClearspotView = nil;
        
        UIColor *statusBarColor = nil;
        UIStatusBarStyle statusBarStyle = UIStatusBarStyleDefault;
        UIView *view = [self topAlertViewForTopAlertObject:topAlertObject animationDelegate:animationDelegate statusBarColor:&statusBarColor statusBarStyle:&statusBarStyle];
        if ([view conformsToProtocol:@protocol(MVMCoreViewProtocol)]) {
            [((UIView <MVMCoreViewProtocol>*)view) updateView:CGRectGetWidth(self.bounds)];
        }
        if (!statusBarColor) {
            statusBarColor = [UIColor whiteColor];
        }
        [self setStatusBarColor:statusBarColor statusBarStyle:statusBarStyle];
        [self showAlertView:view topAlertObject:topAlertObject completionHandler:completionHandler];
    });
}

- (void)updateTopAlertWith:(MVMCoreTopAlertObject *)topAlertObject {
    [self updateMoleculeWith:topAlertObject];
}

- (void)setStatusBarColor:(nullable UIColor *)statusBarColor statusBarStyle:(UIStatusBarStyle)style {
    self.statusBarView.backgroundColor = statusBarColor;
    self.statusBarStyle = style;
    [[MVMCoreUISession sharedGlobal].splitViewController.parentViewController setNeedsStatusBarAppearanceUpdate];
}

- (void)updateAccessibilityForTopAlert:(nullable UIView *)view {
    // Update accessibility with top alert
    if ([view isKindOfClass:[MVMCoreUITopAlertBaseView class]]) {
        [((MVMCoreUITopAlertBaseView *)view) handleAccessibility];
    } else {
        id accessibilityArgument = view;
        if ([view conformsToProtocol:@protocol(AccessibilityProtocol)]) {
            accessibilityArgument = [((id <AccessibilityProtocol>)view) getAccessibilityLayoutChangedArgument];
        }
        UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, accessibilityArgument);
    }
}

- (void)showAlertView:(nullable UIView *)view topAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
    
    __weak typeof(self) weakSelf = self;
    MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
        [MVMCoreDispatchUtility performBlockOnMainThread:^{
            if (weakSelf.currentAlert.superview) {
                [weakSelf.currentAlert removeFromSuperview];
            }
            [weakSelf.alertView addSubview:view];
            [NSLayoutConstraint constraintPinSubviewToSuperview:view];
            weakSelf.currentAlert = view;
            
            [weakSelf.animationDelegate topAlertViewBeginAnimation];
            [weakSelf.superview layoutIfNeeded];
            [UIView animateWithDuration:.5 animations:^{
                weakSelf.height.active = NO;
                [weakSelf.superview layoutIfNeeded];
            } completion:^(BOOL finished) {
                [weakSelf.superview layoutIfNeeded];
                [weakSelf.animationDelegate topAlertViewFinishAnimation];
                
                [weakSelf updateAccessibilityForTopAlert:view];

                [MVMCoreDispatchUtility performBlockInBackground:^{
                    if ([weakSelf.topAlertObject.delegate respondsToSelector:@selector(topAlertViewShown:topAlertObject:)]) {
                        [weakSelf.topAlertObject.delegate topAlertViewShown:view topAlertObject:topAlertObject];
                    }
                    [[MVMCoreUILoggingHandler sharedLoggingHandler] trackTopNotificationShown:view topAlertObject:topAlertObject additionalData:nil];
                    [operation markAsFinished];
                    completionHandler(finished);
                }];
            }];
        }];
    }];
    [[MVMCoreNavigationHandler sharedNavigationHandler] addNavigationOperation:operation];
}

- (void)hideAlertView:(BOOL)forceful completionHandler:(void (^ __nullable)(BOOL finished))completionHandler {
    // If accessible and focused, do not collapse until unfocused.
    if (!forceful && [MVMCoreUIUtility viewContainsAccessiblityFocus:self]) {
        self.hideCompletionHandler = completionHandler;
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accessibilityFocusChanged:) name:UIAccessibilityElementFocusedNotification object:nil];
        return;
    }
    
    __weak typeof(self) weakSelf = self;
    MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
        [MVMCoreDispatchUtility performBlockOnMainThread:^{
            [weakSelf.animationDelegate topAlertViewBeginAnimation];
        
            // accessibility - below line added to notify VI user through voiceover user when the top alert is closed
            UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, [MVMCoreUIUtility hardcodedStringWithKey:@"AccTopAlertClosed"]);
        
            [UIView animateWithDuration:.5 animations:^{
                weakSelf.height.active = YES;
                [weakSelf.superview layoutIfNeeded];
            } completion:^(BOOL finished) {
                [weakSelf.animationDelegate topAlertViewFinishAnimation];
                UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);

                UIView *view = weakSelf.currentAlert;
                if (view.superview) {
                    [view removeFromSuperview];
                }
                
                [MVMCoreDispatchUtility performBlockInBackground:^{
                    if ([weakSelf.topAlertObject.delegate respondsToSelector:@selector(topAlertViewDismissed:)]) {
                        [weakSelf.topAlertObject.delegate topAlertViewDismissed:view];
                    }
                    [operation markAsFinished];
                    if (completionHandler) {
                        completionHandler(finished);
                    }
                    weakSelf.topAlertObject = nil;
                    [MVMCoreDispatchUtility performBlockOnMainThread:^{
                        [weakSelf setStatusBarColor:[UIColor whiteColor] statusBarStyle:UIStatusBarStyleDefault];
                    }];
                }];
            }];
        }];
    }];
    [[MVMCoreNavigationHandler sharedNavigationHandler] addNavigationOperation:operation];
}

- (void)collapseNotification {
    if (self.currentAlert) {
        if ([self.currentAlert isKindOfClass:[MVMCoreUITopAlertExpandableView class]] && ((MVMCoreUITopAlertExpandableView *)self.currentAlert).shortView.label.text.length > 0) {
        
            // We have a short message, collapse to show short message.
            [((MVMCoreUITopAlertExpandableView *)self.currentAlert) collapse];
        } else {
            // Top alert is not collapsable, remove it instead.
            [self hideAlertView:NO completionHandler:NULL];
        }
    }
}

- (void)expandStatusBarView {
    __weak typeof(self) weakSelf = self;
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        weakSelf.statusBarBottomConstraint.active = YES;
        weakSelf.statusBarHeightConstraint.active = NO;
        [weakSelf.superview layoutIfNeeded];
    }];
}

- (void)collapseStatusBarView {
    __weak typeof(self) weakSelf = self;
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        weakSelf.statusBarBottomConstraint.active = NO;
        weakSelf.statusBarHeightConstraint.active = YES;
        [weakSelf.superview layoutIfNeeded];
    }];
}

- (void)resetDefaultBackgroundColor:(UIColor *)backgroundColor basedOnStatusBarStyle:(UIStatusBarStyle)style {
    if (!self.topAlertObject) {
        UIColor *defaultStatusBarBackgroundColor = backgroundColor;
        if (!defaultStatusBarBackgroundColor) {
            defaultStatusBarBackgroundColor = style == UIStatusBarStyleDefault ? [UIColor whiteColor] : [UIColor blackColor];
        }
        
        //color doesn't match the current default value
        if (!CGColorEqualToColor(defaultStatusBarBackgroundColor.CGColor, self.statusBarView.backgroundColor.CGColor)) {
            self.statusBarView.backgroundColor = defaultStatusBarBackgroundColor;
        }
    }
}

/// If the voice over user leaves top alert focus, hide.
- (void)accessibilityFocusChanged:(NSNotification *)notification {
    if (notification.userInfo[UIAccessibilityFocusedElementKey] && ![MVMCoreUIUtility viewContainsAccessiblityFocus:self]) {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityElementFocusedNotification object:nil];
        [self hideAlertView:YES completionHandler:self.hideCompletionHandler];
        self.hideCompletionHandler = nil;
    }
}

@end
