//
//  FLEXAlert.m
//  FLEX
//
//  Created by Tanner Bennett on 8/20/19.
//  Copyright © 2019 Flipboard. All rights reserved.
//

#import "FLEXAlert.h"

@interface FLEXAlert ()
@property (nonatomic, readonly) UIAlertController *_controller;
@property (nonatomic, readonly) NSMutableArray<FLEXAlertAction *> *_actions;
@end

#define FLEXAlertActionMutationAssertion() \
NSAssert(!self._action, @"Cannot mutate action after retreiving underlying UIAlertAction");

@interface FLEXAlertAction ()
@property (nonatomic) UIAlertController *_controller;
@property (nonatomic) NSString *_title;
@property (nonatomic) UIAlertActionStyle _style;
@property (nonatomic) BOOL _disable;
@property (nonatomic) void(^_handler)(UIAlertAction *action);
@property (nonatomic) UIAlertAction *_action;
@end

@implementation FLEXAlert

+ (void)showAlert:(NSString *)title message:(NSString *)message from:(UIViewController *)viewController {
    [self makeAlert:^(FLEXAlert *make) {
        make.title(title).message(message).button(@"Dismiss").cancelStyle();
    } showFrom:viewController];
}

#pragma mark Initialization

- (instancetype)initWithController:(UIAlertController *)controller {
    self = [super init];
    if (self) {
        __controller = controller;
        __actions = [NSMutableArray new];
    }

    return self;
}

+ (UIAlertController *)make:(FLEXAlertBuilder)block withStyle:(UIAlertControllerStyle)style {
    // Create alert builder
    FLEXAlert *alert = [[self alloc] initWithController:
        [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:style]
    ];

    // Configure alert
    block(alert);

    // Add actions
    for (FLEXAlertAction *builder in alert._actions) {
        [alert._controller addAction:builder.action];
    }

    return alert._controller;
}

+ (void)make:(FLEXAlertBuilder)block withStyle:(UIAlertControllerStyle)style showFrom:(UIViewController *)viewController {
    UIAlertController *alert = [self make:block withStyle:style];
    [viewController presentViewController:alert animated:YES completion:nil];
}

+ (void)makeAlert:(FLEXAlertBuilder)block showFrom:(UIViewController *)viewController {
    [self make:block withStyle:UIAlertControllerStyleAlert showFrom:viewController];
}

+ (void)makeSheet:(FLEXAlertBuilder)block showFrom:(UIViewController *)viewController {
    [self make:block withStyle:UIAlertControllerStyleActionSheet showFrom:viewController];
}

+ (UIAlertController *)makeAlert:(FLEXAlertBuilder)block {
    return [self make:block withStyle:UIAlertControllerStyleAlert];
}

+ (UIAlertController *)makeSheet:(FLEXAlertBuilder)block {
    return [self make:block withStyle:UIAlertControllerStyleActionSheet];
}

#pragma mark Configuration

- (FLEXAlertStringProperty)title {
    return ^FLEXAlert *(NSString *title) {
        if (self._controller.title) {
            self._controller.title = [self._controller.title stringByAppendingString:title];
        } else {
            self._controller.title = title;
        }
        return self;
    };
}

- (FLEXAlertStringProperty)message {
    return ^FLEXAlert *(NSString *message) {
        if (self._controller.message) {
            self._controller.message = [self._controller.message stringByAppendingString:message];
        } else {
            self._controller.message = message;
        }
        return self;
    };
}

- (FLEXAlertAddAction)button {
    return ^FLEXAlertAction *(NSString *title) {
        FLEXAlertAction *action = FLEXAlertAction.new.title(title);
        action._controller = self._controller;
        [self._actions addObject:action];
        return action;
    };
}

- (FLEXAlertStringArg)textField {
    return ^FLEXAlert *(NSString *placeholder) {
        [self._controller addTextFieldWithConfigurationHandler:^(UITextField *textField) {
            textField.placeholder = placeholder;
        }];

        return self;
    };
}

- (FLEXAlertTextField)configuredTextField {
    return ^FLEXAlert *(void(^configurationHandler)(UITextField *)) {
        [self._controller addTextFieldWithConfigurationHandler:configurationHandler];
        return self;
    };
}

@end

@implementation FLEXAlertAction

- (FLEXAlertActionStringProperty)title {
    return ^FLEXAlertAction *(NSString *title) {
        FLEXAlertActionMutationAssertion();
        if (self._title) {
            self._title = [self._title stringByAppendingString:title];
        } else {
            self._title = title;
        }
        return self;
    };
}

- (FLEXAlertActionProperty)destructiveStyle {
    return ^FLEXAlertAction *() {
        FLEXAlertActionMutationAssertion();
        self._style = UIAlertActionStyleDestructive;
        return self;
    };
}

- (FLEXAlertActionProperty)cancelStyle {
    return ^FLEXAlertAction *() {
        FLEXAlertActionMutationAssertion();
        self._style = UIAlertActionStyleCancel;
        return self;
    };
}

- (FLEXAlertActionBOOLProperty)enabled {
    return ^FLEXAlertAction *(BOOL enabled) {
        FLEXAlertActionMutationAssertion();
        self._disable = !enabled;
        return self;
    };
}

- (FLEXAlertActionHandler)handler {
    return ^FLEXAlertAction *(void(^handler)(NSArray<NSString *> *)) {
        FLEXAlertActionMutationAssertion();

        // Get weak reference to the alert to avoid block <--> alert retain cycle
        __weak __typeof(self._controller) weakController = self._controller;
        self._handler = ^(UIAlertAction *action) {
            // Strongify that reference and pass the text field strings to the handler
            __strong __typeof(weakController) controller = weakController;
            NSArray *strings = [controller.textFields valueForKeyPath:@"text"];
            handler(strings);
        };

        return self;
    };
}

- (UIAlertAction *)action {
    if (self._action) {
        return self._action;
    }

    self._action = [UIAlertAction
        actionWithTitle:self._title
        style:self._style
        handler:self._handler
    ];
    self._action.enabled = !self._disable;

    return self._action;
}

@end
