#import <Security/Security.h>
#import <Foundation/Foundation.h>

#include <node_api.h>

#define SEC_ATTR_SERVICE       @"Remember The Milk for Mac"

napi_value AddItem(napi_env env, napi_callback_info info) {
  napi_status status;
  size_t argc = 2;
  napi_value handleBuffer[2];

  status = napi_get_cb_info(env, info, &argc, handleBuffer, 0, 0);
  if (status != napi_ok || argc < 2) {
    napi_throw_type_error(env, NULL, "Wrong number of arguments");
    return NULL;
  }

  napi_handle_scope scope;
  status = napi_open_handle_scope(env, &scope);
  if (status != napi_ok) {
    return NULL;
  }

  napi_valuetype valuetype0;
  napi_typeof(env, handleBuffer[0], &valuetype0);

  if (valuetype0 != napi_string) {
    napi_throw_type_error(env, NULL, "Expected 'key' argument to be a string!");
    return NULL;
  }

  size_t keyLength = 0;
  napi_get_value_string_utf8(env, handleBuffer[0], NULL, 0, &keyLength);

  char key[keyLength + 1];
  napi_get_value_string_utf8(env, handleBuffer[0], key, sizeof(key), &keyLength);

  napi_valuetype valuetype1;
  napi_typeof(env, handleBuffer[1], &valuetype1);

  if (valuetype1 != napi_string) {
    napi_throw_type_error(env, NULL, "Expected 'value' argument to be a string!");
    return NULL;
  }

  size_t valueLength = 0;
  napi_get_value_string_utf8(env, handleBuffer[1], NULL, 0, &valueLength);

  char value[valueLength + 1];
  napi_get_value_string_utf8(env, handleBuffer[1], value, sizeof(value), &valueLength);

  NSData* valueData = [[NSString stringWithCString:value encoding:NSUTF8StringEncoding] dataUsingEncoding:NSUTF8StringEncoding];

  NSMutableDictionary * keychainQuery = [NSMutableDictionary dictionaryWithObjectsAndKeys:
    (id)kSecClassGenericPassword, (id)kSecClass,
    SEC_ATTR_SERVICE, (id)kSecAttrService,
    @YES, (id) kSecAttrSynchronizable,
    [NSString stringWithCString:key encoding:NSUTF8StringEncoding], (id)kSecAttrAccount,
    nil];

  SecItemDelete((CFDictionaryRef)keychainQuery);

  [keychainQuery setObject:valueData forKey:(id)kSecValueData];

  SecItemAdd((CFDictionaryRef)keychainQuery, NULL);

  status = napi_close_handle_scope(env, scope);
  if (status != napi_ok) {
    return NULL;
  }

  return NULL;
}

#define DECLARE_NAPI_METHOD(name, func)                                        \
  { name, 0, func, 0, 0, 0, napi_default, 0 }

napi_value Init(napi_env env, napi_value exports) {
  napi_status status;

  napi_property_descriptor descriptors[] = {
    DECLARE_NAPI_METHOD("AddItem", AddItem)
  };

  status = napi_define_properties(env, exports, 1, descriptors);
  if (status != napi_ok) {
    return NULL;
  }

  return exports;
}

NAPI_MODULE(Keychain, Init)
