//
//  MVMCoreUITopAlertExpandableView.m
//  mobilefirst
//
//  Created by Scott Pfeil on 8/18/16.
//  Copyright © 2016 Verizon Wireless. All rights reserved.
//

#import "MVMCoreUITopAlertExpandableView.h"
#import "MVMCoreUITopAlertShortView.h"
#import "MVMCoreUITopAlertMainView.h"
#import <MVMCore/MVMCoreDispatchUtility.h>
#import <MVMCoreUI/MVMCoreTopAlertObject.h>
#import <MVMCoreUI/MVMCoreAlertHandler.h>
#import <MVMCore/MVMCoreBlockOperation.h>
#import <MVMCore/MVMCoreNavigationHandler.h>
#import "MFStyler.h"
#import "NSLayoutConstraint+MFConvenience.h"
#import "MVMCoreUIUtility.h"
#import "MVMCoreUITopAlertView.h"
#import <MVMCoreUI/MVMCoreUI-Swift.h>

@interface MVMCoreUITopAlertExpandableView ()

@property (nonatomic) BOOL expanded;

@property (nullable, weak, nonatomic) id <MVMCoreTopAlertAnimationDelegateProtocol> animationDelegate;

@property (nullable, weak, nonatomic) UIView *viewToLayout;

@property (nullable, strong, nonatomic) NSLayoutConstraint *topLabelConstraintBottom;
@property (nullable, strong, nonatomic) NSLayoutConstraint *topConstraint;
@property (nullable, strong, nonatomic) NSLayoutConstraint *shortViewHeight;

// Sets up the short view.
- (void)setupTopMessage:(nullable NSString *)topMessage;

// Sets up the button view.
- (void)setupTopAlertWithButton:(MVMCoreUITopAlertMainView *)topAlertWithButton;

// Sets up the whole view without setting button action.
- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle;

// Sets up the whole view while setting button action.
- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData;

@end

@implementation MVMCoreUITopAlertExpandableView

- (void)handleAccessibility {
    
    if (self.shortView.label.text.length > 0 && !self.expanded) {
        UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.shortView.label);
    } else if (self.buttonView.label.text.length > 0) {
        UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, self.buttonView.label);
    } else {
        UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
    }
}

#pragma mark - Setup View

- (void)updateView:(CGFloat)size {
    [super updateView:size];
    [self.shortView updateView:size];
    [self.buttonView updateView:size];
}

- (nullable instancetype)init {
    if (self = [super init]) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        self.clipsToBounds = YES;
        self.expanded = NO;
    }
    return self;
}

- (nullable instancetype)initWithTopAlertObject:(nonnull MVMCoreTopAlertObject *)topAlertObject animationDelegate:(nullable id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate viewToLayout:(nonnull UIView *)viewTolayout {
    if (self = [self init]) {
        self.animationDelegate = animationDelegate;
        self.viewToLayout = viewTolayout;
        
        if (topAlertObject.useNewStyle) {
            
            // New style, collapses automatically after x time if there is a top message.
            self.collapseTime = topAlertObject.topAlertDismissTime;
            if (topAlertObject.persistent && topAlertObject.topMessage) {
                _collapseAutomaticallyAfterExpanded = YES;
            }
            
            // Setup the views.
            [self setupTopMessage:topAlertObject.topMessage];
            MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithTopAlertObject:topAlertObject animationDelegate:animationDelegate];
            [self setupTopAlertWithButton:topAlertWithButton];

            // Sets the color
            self.shortView.label.textColor = topAlertObject.textColor ?: [[MVMCoreUITopAlertView sharedGlobal] getContentColorForType:topAlertObject.type];
            self.backgroundColor = topAlertObject.backgroundColor ?: [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type];
            
            if (topAlertWithButton.label.text.length > 0) {
                [self expand:NO];
            }
        } else {
        
            // Old style, has no top alert and main view is limited.
            self.backgroundColor = [[MVMCoreUITopAlertView sharedGlobal] getBackgroundColorForType:topAlertObject.type];
            UIColor *contentColor = [[MVMCoreUITopAlertView sharedGlobal] getContentColorForType:topAlertObject.type];
            [self setupTopMessage:nil];
            self.shortView.label.textColor = contentColor;
            MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:self.backgroundColor contentColor:contentColor message:topAlertObject.message subMessage:nil closeButton:YES animationDelegate:animationDelegate];
            [self setupTopAlertWithButton:topAlertWithButton];
            [self expand:NO];
        }
    }
    return self;
}

- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate viewToLayout:(nonnull UIView *)viewTolayout {
    if (self = [self init]) {
        self.animationDelegate = animationDelegate;
        self.viewToLayout = viewTolayout;
        [self setupViewWithTopMessage:topMessage message:message subMessage:nil contentColor:contentColor buttonTitle:buttonTitle];
    }
    return self;
}

- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle animationDelegate:(nullable id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate viewToLayout:(nonnull UIView *)viewTolayout {
    if (self = [self init]) {
        self.animationDelegate = animationDelegate;
        self.viewToLayout = viewTolayout;
        [self setupViewWithTopMessage:topMessage message:message subMessage:subMessage contentColor:contentColor buttonTitle:buttonTitle];
    }
    return self;
}

- (nullable instancetype)initWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData animationDelegate:(nullable id <MVMCoreTopAlertAnimationDelegateProtocol>)animationDelegate viewToLayout:(nonnull UIView *)viewTolayout {
    if (self = [self init]) {
        self.animationDelegate = animationDelegate;
        self.viewToLayout = viewTolayout;
        [self setupViewWithTopMessage:topMessage message:message subMessage:subMessage contentColor:contentColor actionMap:actionMap additionalData:additionalData];
    }
    return self;
}

- (void)defaultSetup {
    if (!self.shortView) {
        self.translatesAutoresizingMaskIntoConstraints = NO;
        self.clipsToBounds = YES;
        _collapseAutomaticallyAfterExpanded = YES;
        self.viewToLayout = MVMCoreUITopAlertView.sharedGlobal.superview;
        self.expanded = NO;
        [self setupTopMessage:nil];
        MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] init];
        [topAlertWithButton defaultSetup];
        [self setupTopAlertWithButton:topAlertWithButton];
    }
}

- (void)setupTopMessage:(nullable NSString *)topMessage {
    
    MVMCoreUITopAlertShortView *shortView = [[MVMCoreUITopAlertShortView alloc] initWithColor:[UIColor clearColor] message:nil actionMap:nil additionalData:nil topAlertObject:nil];
    shortView.label.font = [MFStyler fontB2];
    [self addSubview:shortView];
    self.shortView = shortView;

    [NSLayoutConstraint constraintPinSubview:shortView pinTop:YES topConstant:0 pinBottom:NO bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0];
    self.topLabelConstraintBottom = [NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:shortView attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
    self.topLabelConstraintBottom.active = YES;
    
    self.shortViewHeight = [NSLayoutConstraint constraintWithItem:shortView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:0];
    [self setTopMessage:topMessage];
}

- (void)setupTopAlertWithButton:(MVMCoreUITopAlertMainView *)topAlertWithButton {
    topAlertWithButton.label.alpha = 0;
    topAlertWithButton.button.alpha = 0;
    topAlertWithButton.backgroundColor = [UIColor clearColor];
    [self insertSubview:topAlertWithButton belowSubview:self.shortView];
    self.buttonView = topAlertWithButton;
        
    self.topConstraint = [NSLayoutConstraint constraintWithItem:topAlertWithButton attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.shortView attribute:NSLayoutAttributeBottom multiplier:1 constant:0];
    [NSLayoutConstraint constraintPinSubview:topAlertWithButton pinTop:NO topConstant:0 pinBottom:YES bottomConstant:0 pinLeft:YES leftConstant:0 pinRight:YES rightConstant:0];
}

- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle {
    
    [self setupTopMessage:topMessage];
    self.shortView.label.textColor = contentColor;

    MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:[UIColor clearColor] contentColor:contentColor message:message subMessage:subMessage buttonTitle:buttonTitle userActionHandler:nil];
    [self setupTopAlertWithButton:topAlertWithButton];
}

- (void)setupViewWithTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData {
    
    [self setupTopMessage:topMessage];
    self.shortView.label.textColor = contentColor;

    MVMCoreUITopAlertMainView *topAlertWithButton = [[MVMCoreUITopAlertMainView alloc] initWithColor:[UIColor clearColor] contentColor:contentColor message:message subMessage:subMessage actionMap:actionMap additionalData:additionalData];
    [self setupTopAlertWithButton:topAlertWithButton];
}

#pragma mark - Setters

- (void)setTopMessage:(nullable NSString *)topMessage {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        self.shortView.label.text = topMessage;
        self.shortView.label.accessibilityLabel = topMessage;
        [MVMCoreUITopAlertBaseView amendAccesibilityLabelForView:self.shortView.label];
        
        if (topMessage && (!self.onlyShowTopMessageWhenCollapsed || !self.expanded)) {
            self.shortViewHeight.active = NO;
        } else if (!topMessage || (self.onlyShowTopMessageWhenCollapsed && self.expanded)) {
            self.shortViewHeight.active = YES;
        }
    }];
}

- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor actionMap:(nullable NSDictionary *)actionMap additionalData:(nullable NSDictionary *)additionalData {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        [self setTopMessage:topMessage];
        [self.buttonView setupWithMessage:message subMessage:subMessage color:contentColor actionMap:actionMap additionalData:additionalData];
    }];
}

- (void)setTopMessage:(nullable NSString *)topMessage message:(nullable NSString *)message subMessage:(nullable NSString *)subMessage contentColor:(nonnull UIColor *)contentColor buttonTitle:(nullable NSString *)buttonTitle userActionHandler:(nullable void (^)(id  _Nonnull sender))userActionHandler {
    [MVMCoreDispatchUtility performBlockOnMainThread:^{
        [self setTopMessage:topMessage];
        [self.buttonView setupWithMessage:message subMessage:subMessage color:contentColor buttonTitle:buttonTitle userActionHandler:userActionHandler];
    }];
}

- (void)setButtonPressToExpand {
    __weak typeof(self) weakSelf = self;
    [self.buttonView.button addActionBlockWithEvent:UIControlEventTouchUpInside :^(Button * _Nonnull button) {
        if (weakSelf) {
            [weakSelf expand:YES];
        }
    }];
}

- (void)setButtonPressToCollapse {
    __weak typeof(self) weakSelf = self;
    [self.buttonView.button addActionBlockWithEvent:UIControlEventTouchUpInside :^(Button * _Nonnull button) {
        if (weakSelf) {
            [weakSelf collapse];
        }
    }];
}

- (void)setShortViewPressToExpand {
    __weak typeof(self) weakSelf = self;
    self.shortView.label.accessibilityTraits = UIAccessibilityTraitButton;
    [self.shortView.button addActionBlockWithEvent:UIControlEventTouchUpInside :^(Button * _Nonnull button) {
        if (weakSelf) {
            [weakSelf expand:YES];
        }
    }];
}

- (void)setShortViewPressToCollapse {
    __weak typeof(self) weakSelf = self;
    self.shortView.label.accessibilityTraits = UIAccessibilityTraitButton;
    [self.shortView.button addActionBlockWithEvent:UIControlEventTouchUpInside :^(Button * _Nonnull button) {
        if (weakSelf) {
            [weakSelf collapse];
        }
    }];
}

- (void)setOnlyShowTopMessageWhenCollapsed:(BOOL)onlyShowTopMessageWhenCollapsed {
    _onlyShowTopMessageWhenCollapsed = onlyShowTopMessageWhenCollapsed;
    if (onlyShowTopMessageWhenCollapsed && self.expanded) {
        [MVMCoreDispatchUtility performBlockOnMainThread:^{
            self.shortView.label.alpha = 0;
            self.shortViewHeight.active = YES;
        }];
    } else if (!onlyShowTopMessageWhenCollapsed && self.expanded) {
        [MVMCoreDispatchUtility performBlockOnMainThread:^{
            self.shortView.label.alpha = 1;
            self.shortViewHeight.active = NO;
        }];
    }
}

- (void)setCollapseAutomaticallyAfterExpanded:(BOOL)collapseAutomaticallyAfterExpanded {
    _collapseAutomaticallyAfterExpanded = collapseAutomaticallyAfterExpanded;
    if (collapseAutomaticallyAfterExpanded) {
        [self autoCollapse];
    }
}

#pragma mark - Expand/Collapse

- (void)expand:(BOOL)animated {
    if (!self.expanded) {
        __weak typeof(self) weakSelf = self;
        MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
            [MVMCoreDispatchUtility performBlockOnMainThread:^{
                [weakSelf performExpansion:animated onCompletion:^{
                    [operation markAsFinished];
                }];
            }];
        }];
        [[MVMCoreNavigationHandler sharedNavigationHandler] addNavigationOperation:operation];
    }
}

- (void)performExpansion:(BOOL)animated onCompletion:(void(^)(void))completionHandler {
    // Must notify animation delegate before animating.
    if (animated && self.animationDelegate) {
        [self.animationDelegate topAlertViewBeginAnimation];
    }
    
    [self.viewToLayout layoutIfNeeded];
    self.topLabelConstraintBottom.active = NO;
    self.topConstraint.active = YES;
    self.expanded = YES;
    
    void(^animation)(void) = ^(void) {
        self.buttonView.button.alpha = 1;
        self.buttonView.label.alpha = 1;
        if (self.onlyShowTopMessageWhenCollapsed) {
            self.shortViewHeight.active = YES;
        }
        [self.viewToLayout layoutIfNeeded];
    };
    
    //accessibility - added to make only top alert label and close button accessible. Posted notification when top alert is displayed
    self.accessibilityElements = @[self.buttonView];
    self.shortView.isAccessibilityElement = NO;
    
    void(^completion)(void) = ^(void) {
        UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, self.buttonView.label);
        completionHandler();
    };
    if (animated) {
        [UIView animateWithDuration:.5 animations:animation completion:^(BOOL finished) {
            [self.viewToLayout layoutIfNeeded];
            
            // Must notify animation delegate when animating finished.
            [MVMCoreDispatchUtility performBlockInBackground:^{
                if (self.animationDelegate) {
                    [self.animationDelegate topAlertViewFinishAnimation];
                }
            }];
            completion();
        }];
    } else {
        animation();
        completion();
    }
    
    // Collapse after 5 seconds (if the view still exists)
    [self autoCollapse];
}

- (void)autoCollapse {
    if (self.collapseAutomaticallyAfterExpanded) {
        __weak typeof(self) weakSelf = self;
        NSInteger dismissTime;
        if (self.collapseTime > 0) {
            dismissTime = self.collapseTime;
        } else {
            dismissTime = TopAlertDismissTime;
        }
        dispatch_time_t dispatchTime = dispatch_time(DISPATCH_TIME_NOW, dismissTime * NSEC_PER_SEC);
        dispatch_after(dispatchTime, dispatch_get_main_queue(), ^(void){
            typeof(self) strongSelf = weakSelf;
            if (strongSelf && strongSelf.expanded && strongSelf.collapseAutomaticallyAfterExpanded) {
                // If accessibility focused, delay collapse.
                if ([MVMCoreUIUtility viewContainsAccessiblityFocus:strongSelf]) {
                    [[NSNotificationCenter defaultCenter] addObserver:strongSelf selector:@selector(accessibilityFocusChanged:) name:UIAccessibilityElementFocusedNotification object:nil];
                } else {
                    [strongSelf collapse];
                }
            }
        });
    }
}

- (void)collapse {
    if (self.expanded) {
        __weak typeof(self) weakSelf = self;
        MVMCoreBlockOperation *operation = [MVMCoreBlockOperation blockOperationWithBlock:^(MVMCoreBlockOperation * _Nonnull operation) {
            [MVMCoreDispatchUtility performBlockOnMainThread:^{
                [weakSelf performCollapseAnimationThen:^{
                    [operation markAsFinished];
                }];
            }];
        }];
        [[MVMCoreNavigationHandler sharedNavigationHandler] addNavigationOperation:operation];
    }
}

- (void)performCollapseAnimationThen:(void(^)(void))completionHandler {
    // Must notify animation delegate before animating.
    if (self.animationDelegate) {
        [self.animationDelegate topAlertViewBeginAnimation];
    }
    [self.viewToLayout layoutIfNeeded];
    self.topConstraint.active = NO;
    self.topLabelConstraintBottom.active = YES;
    self.expanded = NO;
    [UIView animateWithDuration:.5 animations:^{
        [self.viewToLayout layoutIfNeeded];
        self.buttonView.button.alpha = 0;
        self.buttonView.label.alpha = 0;
        self.shortViewHeight.active = NO;
    } completion:^(BOOL finished) {
        [self.viewToLayout layoutIfNeeded];
        self.accessibilityElements = @[self.shortView.label];
        UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
        // Must notify animation delegate when animating finished.
        [MVMCoreDispatchUtility performBlockInBackground:^{
            if (self.animationDelegate) {
                [self.animationDelegate topAlertViewFinishAnimation];
            }
        }];
        completionHandler();
    }];
}

- (void)accessibilityFocusChanged:(NSNotification *)notification {
    if (notification.userInfo[UIAccessibilityFocusedElementKey] && ![MVMCoreUIUtility viewContainsAccessiblityFocus:self]) {
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIAccessibilityElementFocusedNotification object:nil];
        [self collapse];
    }
}

@end
