// Copyright 2015-present 650 Industries. All rights reserved.

#import "EXAppLoader.h"
#import "EXErrorView.h"
#import "EXEnvironment.h"
#import "EXKernel.h"
#import "EXKernelAppRecord.h"
#import "EXUtil.h"

@interface EXErrorView ()

@property (nonatomic, strong) UILabel *lblError;
@property (nonatomic, strong) UIButton *btnRetry;
@property (nonatomic, strong) UIButton *btnBack;
@property (nonatomic, strong) UILabel *lblUrl;
@property (nonatomic, strong) UILabel *lblErrorDetail;
@property (nonatomic, strong) UIScrollView *vContainer;

- (void)_onTapRetry;

@end

@implementation EXErrorView

- (instancetype)initWithFrame:(CGRect)frame
{
  if (self = [super initWithFrame:frame]) {
    self.backgroundColor = [UIColor whiteColor];
    
    self.vContainer = [[UIScrollView alloc] init];
    [self addSubview:_vContainer];

    // error description label
    self.lblError = [[UILabel alloc] init];
    _lblError.numberOfLines = 0;
    _lblError.textAlignment = NSTextAlignmentCenter;
    _lblError.font = [UIFont systemFontOfSize:14.0f];
    [_vContainer addSubview:_lblError];
    
    // retry button
    self.btnRetry = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [_btnRetry setTitle:@"Try again" forState:UIControlStateNormal];
    [_btnRetry addTarget:self action:@selector(_onTapRetry) forControlEvents:UIControlEventTouchUpInside];
    [_vContainer addSubview:_btnRetry];
    
    // back button
    self.btnBack = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [_btnBack setTitle:@"Go back to Expo Home" forState:UIControlStateNormal];
    [_btnBack addTarget:self action:@selector(_onTapBack) forControlEvents:UIControlEventTouchUpInside];
    [_vContainer addSubview:_btnBack];
    
    for (UIButton *btnToStyle in @[ _btnRetry, _btnBack ]) {
      [btnToStyle setTintColor:[EXUtil colorWithRGB:0x49a7e8]];
      [btnToStyle.titleLabel setFont:[UIFont boldSystemFontOfSize:14.0f]];
    }
    
    // url label
    self.lblUrl = [[UILabel alloc] init];
    _lblUrl.numberOfLines = 0;
    _lblUrl.textAlignment = NSTextAlignmentCenter;
    [_vContainer addSubview:_lblUrl];

    // error detail label
    self.lblErrorDetail = [[UILabel alloc] init];
    _lblErrorDetail.numberOfLines = 0;
    _lblErrorDetail.textAlignment = NSTextAlignmentLeft;
    [_vContainer addSubview:_lblErrorDetail];
    
    for (UILabel *lblToStyle in @[ _lblUrl, _lblErrorDetail ]) {
      lblToStyle.font = [UIFont systemFontOfSize:14.0f];
      lblToStyle.textColor = [UIColor lightGrayColor];
    }
  }
  return self;
}

- (void)setType:(EXFatalErrorType)type
{
  _type = type;
  NSString *appOwnerName = @"the requested app";
  if (_appRecord) {
    if (_appRecord == [EXKernel sharedInstance].appRegistry.homeAppRecord) {
      appOwnerName = @"Expo";
    } else if (_appRecord.appLoader.manifest && _appRecord.appLoader.manifest[@"name"]) {
      appOwnerName = [NSString stringWithFormat:@"\"%@\"", _appRecord.appLoader.manifest[@"name"]];
    }
  }

  switch (type) {
    case kEXFatalErrorTypeLoading: {
      _lblError.text = [NSString stringWithFormat:@"There was a problem loading %@.", appOwnerName];
      if (_error.code == kCFURLErrorNotConnectedToInternet) {
        _lblError.text = [NSString stringWithFormat:@"%@ Make sure you're connected to the internet.", _lblError.text];
      } else if (_appRecord.appLoader.manifestUrl) {
        NSString *url = _appRecord.appLoader.manifestUrl.absoluteString;
        if ([self _urlLooksLikeLAN:url]) {
          NSString *extraLANPermissionText = @"";
          if (@available(iOS 14, *)) {
            extraLANPermissionText = @", and that you have granted Expo Go the Local Network permission in the Settings app,";
          }
          _lblError.text = [NSString stringWithFormat:
                            @"%@\n\nIt looks like you may be using a LAN URL. "
                            "Make sure your device is on the same network as the server%@ or try using the tunnel connection type.", _lblError.text, extraLANPermissionText];
        }
      }
      break;
    }
    case kEXFatalErrorTypeException: {
      _lblError.text = [NSString stringWithFormat:@"There was a problem running %@.", appOwnerName];
      break;
    }
  }
  [self _resetUIState];
}

- (void)setError:(NSError *)error
{
  _error = error;
  _lblErrorDetail.text = [error localizedDescription];
  [self _resetUIState];
}

- (void)setAppRecord:(EXKernelAppRecord *)appRecord
{
  _appRecord = appRecord;
  [self _resetUIState];
}

- (void)layoutSubviews
{
  [super layoutSubviews];

  _vContainer.frame = self.bounds;
  CGFloat maxLabelWidth = self.bounds.size.width - 32.0f;

  _lblError.frame = CGRectMake(0, 0, maxLabelWidth, CGFLOAT_MAX);
  [_lblError sizeToFit];
  _lblError.center = CGPointMake(self.bounds.size.width * 0.5f, self.bounds.size.height * 0.25f);

  _btnRetry.frame = CGRectMake(0, 0, self.bounds.size.width, 24.0f);
  _btnRetry.center = CGPointMake(_lblError.center.x, CGRectGetMaxY(_lblError.frame) + 32.0f);
  
  _btnBack.frame = CGRectMake(0, 0, self.bounds.size.width, 24.0f);
  _btnBack.center = CGPointMake(_lblError.center.x, CGRectGetMaxY(_btnRetry.frame) + 24);
  
  _lblUrl.frame = CGRectMake(0, 0, self.bounds.size.width - 48.0f, CGFLOAT_MAX);
  [_lblUrl sizeToFit];
  _lblUrl.center = CGPointMake(_lblError.center.x, CGRectGetMaxY(_btnBack.frame) + 12.0f + CGRectGetMidY(_lblUrl.bounds));

  _lblErrorDetail.frame = CGRectMake(0, 0, maxLabelWidth, CGFLOAT_MAX);
  [_lblErrorDetail sizeToFit];

  _lblErrorDetail.center = CGPointMake(_lblError.center.x, CGRectGetMaxY(_lblUrl.frame) + 24.0f + CGRectGetMidY(_lblErrorDetail.bounds));

  _vContainer.contentSize = CGSizeMake(_vContainer.bounds.size.width, CGRectGetMaxY(_lblErrorDetail.frame) + 12.0f);
}

#pragma mark - Internal

- (void)_resetUIState
{
  EXKernelAppRecord *homeRecord = [EXKernel sharedInstance].appRegistry.homeAppRecord;
  _btnBack.hidden = (!homeRecord || _appRecord == homeRecord);
  _lblUrl.hidden = (!homeRecord && ![self _isDevDetached]);
  _lblUrl.text = _appRecord.appLoader.manifestUrl.absoluteString;
  // TODO: maybe hide retry (see BrowserErrorView)
  [self setNeedsLayout];
}

- (void)_onTapRetry
{
  if (_delegate) {
    [_delegate errorViewDidSelectRetry:self];
  }
}

- (void)_onTapBack
{
  if ([EXKernel sharedInstance].browserController) {
    [[EXKernel sharedInstance].browserController moveHomeToVisible];
  }
}

- (BOOL)_urlLooksLikeLAN:(NSString *)url
{
  return (
    url && (
      [url rangeOfString:@".local"].length > 0 ||
      [url rangeOfString:@"192."].length > 0 ||
      [url rangeOfString:@"10."].length > 0 ||
      [url rangeOfString:@"172."].length > 0
    )
  );
}

- (BOOL)_isDevDetached
{
  return [EXEnvironment sharedEnvironment].isDetached && [EXEnvironment sharedEnvironment].isDebugXCodeScheme;
}

@end
