/**
 * @description
 * HTTP code snippet generator for Swift using NSURLSession.
 *
 * @author
 * @thibaultCha
 *
 * for any questions or issues regarding the generated code snippet, please open an issue mentioning the author.
 */

'use strict';

var util = require('util');
var helpers = require('./helpers');
var CodeBuilder = require('../../helpers/code-builder');

module.exports = function(source, options) {
  var opts = util._extend(
    {
      indent: '  ',
      pretty: true,
      timeout: '10'
    },
    options
  );

  var code = new CodeBuilder(opts.indent);

  // Markers for headers to be created as litteral objects and later be set on the NSURLRequest if exist
  var req = {
    hasHeaders: false,
    hasBody: false
  };

  // We just want to make sure people understand that is the only dependency
  code.push('import Foundation');

  if (Object.keys(source.allHeaders).length) {
    req.hasHeaders = true;
    code.blank().push(helpers.literalDeclaration('headers', source.allHeaders, opts));
  }

  if (source.postData.text || source.postData.jsonObj || source.postData.params) {
    req.hasBody = true;

    switch (source.postData.mimeType) {
      case 'application/x-www-form-urlencoded':
        // By appending parameters one by one in the resulting snippet,
        // we make it easier for the user to edit it according to his or her needs after pasting.
        // The user can just add/remove lines adding/removing body parameters.
        code
          .blank()
          .push(
            'let postData = NSMutableData(data: "%s=%s".data(using: String.Encoding.utf8)!)',
            source.postData.params[0].name,
            source.postData.params[0].value
          );
        for (var i = 1, len = source.postData.params.length; i < len; i++) {
          code.push(
            'postData.append("&%s=%s".data(using: String.Encoding.utf8)!)',
            source.postData.params[i].name,
            source.postData.params[i].value
          );
        }
        break;

      case 'application/json':
        if (source.postData.jsonObj) {
          code
            .push(
              helpers.literalDeclaration('parameters', source.postData.jsonObj, opts),
              'as [String : Any]'
            )
            .blank()
            .push('let postData = JSONSerialization.data(withJSONObject: parameters, options: [])');
        }
        break;

      case 'multipart/form-data':
        /**
         * By appending multipart parameters one by one in the resulting snippet,
         * we make it easier for the user to edit it according to his or her needs after pasting.
         * The user can just edit the parameters NSDictionary or put this part of a snippet in a multipart builder method.
         */
        code
          .push(helpers.literalDeclaration('parameters', source.postData.params, opts))
          .blank()
          .push('let boundary = "%s"', source.postData.boundary)
          .blank()
          .push('var body = ""')
          .push('var error: NSError? = nil')
          .push('for param in parameters {')
          .push(1, 'let paramName = param["name"]!')
          .push(1, 'body += "--\\(boundary)\\r\\n"')
          .push(1, 'body += "Content-Disposition:form-data; name=\\"\\(paramName)\\""')
          .push(1, 'if let filename = param["fileName"] {')
          .push(2, 'let contentType = param["content-type"]!')
          .push(
            2,
            'let fileContent = String(contentsOfFile: filename, encoding: String.Encoding.utf8)'
          )
          .push(2, 'if (error != nil) {')
          .push(3, 'print(error)')
          .push(2, '}')
          .push(2, 'body += "; filename=\\"\\(filename)\\"\\r\\n"')
          .push(2, 'body += "Content-Type: \\(contentType)\\r\\n\\r\\n"')
          .push(2, 'body += fileContent')
          .push(1, '} else if let paramValue = param["value"] {')
          .push(2, 'body += "\\r\\n\\r\\n\\(paramValue)"')
          .push(1, '}')
          .push('}');
        break;

      default:
        code
          .blank()
          .push(
            'let postData = NSData(data: "%s".data(using: String.Encoding.utf8)!)',
            source.postData.text
          );
    }
  }

  code
    .blank()
    // NSURLRequestUseProtocolCachePolicy is the default policy, let's just always set it to avoid confusion.
    .push('let request = NSMutableURLRequest(url: NSURL(string: "%s")! as URL,', source.fullUrl)
    .push('                                        cachePolicy: .useProtocolCachePolicy,')
    .push(
      '                                    timeoutInterval: %s)',
      parseInt(opts.timeout, 10).toFixed(1)
    )
    .push('request.httpMethod = "%s"', source.method);

  if (req.hasHeaders) {
    code.push('request.allHTTPHeaderFields = headers');
  }

  if (req.hasBody) {
    code.push('request.httpBody = postData as Data');
  }

  code
    .blank()
    // Retrieving the shared session will be less verbose than creating a new one.
    .push('let session = URLSession.shared')
    .push(
      'let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in'
    )
    .push(1, 'if (error != nil) {')
    .push(2, 'print(error)')
    .push(1, '} else {')
    // Casting the NSURLResponse to NSHTTPURLResponse so the user can see the status     .
    .push(2, 'let httpResponse = response as? HTTPURLResponse')
    .push(2, 'print(httpResponse)')
    .push(1, '}')
    .push('})')
    .blank()
    .push('dataTask.resume()');

  return code.join();
};

module.exports.info = {
  key: 'nsurlsession',
  title: 'NSURLSession',
  link:
    'https://developer.apple.com/library/mac/documentation/Foundation/Reference/NSURLSession_class/index.html',
  description: "Foundation's NSURLSession request"
};
