/*
 *  Copyright 2014 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#import "ARDAppEngineClient.h"

#import "sdk/objc/base/RTCLogging.h"

#import "ARDJoinResponse.h"
#import "ARDMessageResponse.h"
#import "ARDSignalingMessage.h"
#import "ARDUtilities.h"

// TODO(tkchin): move these to a configuration object.
static NSString *const kARDRoomServerHostUrl = @"https://appr.tc";
static NSString *const kARDRoomServerJoinFormat = @"https://appr.tc/join/%@";
static NSString *const kARDRoomServerJoinFormatLoopback =
    @"https://appr.tc/join/%@?debug=loopback";
static NSString *const kARDRoomServerMessageFormat =
    @"https://appr.tc/message/%@/%@";
static NSString *const kARDRoomServerLeaveFormat =
    @"https://appr.tc/leave/%@/%@";

static NSString *const kARDAppEngineClientErrorDomain = @"ARDAppEngineClient";
static NSInteger const kARDAppEngineClientErrorBadResponse = -1;

@implementation ARDAppEngineClient

#pragma mark - ARDRoomServerClient

- (void)joinRoomWithRoomId:(NSString *)roomId
                isLoopback:(BOOL)isLoopback
         completionHandler:(void (^)(ARDJoinResponse *response,
                                     NSError *error))completionHandler {
  NSParameterAssert(roomId.length);

  NSString *urlString = nil;
  if (isLoopback) {
    urlString =
        [NSString stringWithFormat:kARDRoomServerJoinFormatLoopback, roomId];
  } else {
    urlString = [NSString stringWithFormat:kARDRoomServerJoinFormat, roomId];
  }

  NSURL *roomURL = [NSURL URLWithString:urlString];
  RTCLog(@"Joining room:%@ on room server.", roomId);
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:roomURL];
  request.HTTPMethod = @"POST";
  [NSURLConnection
       sendAsyncRequest:request
      completionHandler:^(
          NSURLResponse *response __unused, NSData *data, NSError *error) {
        if (error) {
          if (completionHandler) {
            completionHandler(nil, error);
          }
          return;
        }
        ARDJoinResponse *joinResponse =
            [ARDJoinResponse responseFromJSONData:data];
        if (!joinResponse) {
          if (completionHandler) {
            NSError *err = [[self class] badResponseError];
            completionHandler(nil, err);
          }
          return;
        }
        if (completionHandler) {
          completionHandler(joinResponse, nil);
        }
      }];
}

- (void)sendMessage:(ARDSignalingMessage *)message
            forRoomId:(NSString *)roomId
             clientId:(NSString *)clientId
    completionHandler:(void (^)(ARDMessageResponse *response,
                                NSError *error))completionHandler {
  NSParameterAssert(message);
  NSParameterAssert(roomId.length);
  NSParameterAssert(clientId.length);

  NSData *messageData = [message JSONData];
  NSString *urlString =
      [NSString stringWithFormat:kARDRoomServerMessageFormat, roomId, clientId];
  NSURL *url = [NSURL URLWithString:urlString];
  RTCLog(@"C->RS POST: %@", message);
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  request.HTTPMethod = @"POST";
  request.HTTPBody = messageData;
  [NSURLConnection sendAsyncRequest:request
                  completionHandler:^(NSURLResponse *response __unused,
                                      NSData *data,
                                      NSError *responseError) {
                    if (responseError) {
                      if (completionHandler) {
                        completionHandler(nil, responseError);
                      }
                      return;
                    }
                    ARDMessageResponse *messageResponse =
                        [ARDMessageResponse responseFromJSONData:data];
                    if (!messageResponse) {
                      if (completionHandler) {
                        NSError *err = [[self class] badResponseError];
                        completionHandler(nil, err);
                      }
                      return;
                    }
                    if (completionHandler) {
                      completionHandler(messageResponse, nil);
                    }
                  }];
}

- (void)leaveRoomWithRoomId:(NSString *)roomId
                   clientId:(NSString *)clientId
          completionHandler:(void (^)(NSError *error))completionHandler {
  NSParameterAssert(roomId.length);
  NSParameterAssert(clientId.length);

  NSString *urlString =
      [NSString stringWithFormat:kARDRoomServerLeaveFormat, roomId, clientId];
  NSURL *url = [NSURL URLWithString:urlString];
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
  request.HTTPMethod = @"POST";

  RTCLog(@"C->RS: BYE");
  __block NSError *error = nil;

  // We want a synchronous request so that we know that we've left the room on
  // room server before we do any further work.
  dispatch_semaphore_t sem = dispatch_semaphore_create(0);
  [NSURLConnection
       sendAsyncRequest:request
      completionHandler:^(
          NSURLResponse *response __unused, NSData *data __unused, NSError *e) {
        if (e) {
          error = e;
        }
        dispatch_semaphore_signal(sem);
      }];

  dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
  if (error) {
    RTCLogError(@"Error leaving room %@ on room server: %@",
                roomId,
                error.localizedDescription);
    if (completionHandler) {
      completionHandler(error);
    }
    return;
  }
  RTCLog(@"Left room:%@ on room server.", roomId);
  if (completionHandler) {
    completionHandler(nil);
  }
}

#pragma mark - Private

+ (NSError *)badResponseError {
  NSError *error = [[NSError alloc]
      initWithDomain:kARDAppEngineClientErrorDomain
                code:kARDAppEngineClientErrorBadResponse
            userInfo:@{
              NSLocalizedDescriptionKey : @"Error parsing response.",
            }];
  return error;
}

@end
