var rest = require('restler');
var async = require('async');
var uuid = require('uuid/v4');
var restq = require('restler-q');
var http = require("http");
var qs = require("qs");


function RestHelper(logger, settings) {
	this.logger = logger;
	this.settings = settings;
	this.restTasks = {};
}

RestHelper.prototype = {
	getUrl: function (url, baseUrl) {
		var base = this.settings.restful.url + baseUrl + this.settings.restful.version + "/" + url;
		return base;
	},
	preLog: function (tempUrl, tempParams) {
		
	},
	checkJson: function (type) {
		if (type === 'patchJson' || type === 'putJson' || type === 'postJson' || type === 'json') {
			return true;
		} else {
			return false;
		}
	},
	reflashToken: function (data, respones, taskId) {
		// var self=this,method=self.restTasks[taskId].type,context=self.restTasks[taskId].context,req=context.req,res=context.res;
		// if(req.session.passport&&req.session.passport.user&&req.session.passport.user.token&&req.session.passport.user.user_info){
		// 	var tempParams={
		// 		'grant_type':'refresh_token', 
		// 		'refresh_token':req.session.passport.user.refreshToken,
		// 		'account':req.session.passport.user.user_info.tenant_id
		// 	};
		// 	rest.postJson(self.getUrl('auth/tokens'),tempParams,{
		// 		headers: { 'Content-Type': 'application/json','Accept': 'application/json' }})
		// 		.on('success',function(data,response){
		// 			console.log(data);
		// 			console.log(req.session); 
		// 			if(data.access_token){
		// 				req.session.passport.user.token=data.access_token;
		// 				req.session.passport.user.refreshToken=data.refresh_token;
		// 				req.session.save(function(err){ console.log(err);}); 
		// 				if(self.checkJson(method)){
		// 					context.options.accessToken=req.session.passport.user.token; 
		// 					rest[method](context.url,context.data,context.options)
		// 					.on('success',function(data,response){
		// 						delete self.restTasks[taskId];
		// 						if(context.asyncMap){
		// 							context.callback(null, data);
		// 						}else{
		// 							context.callback(data,response);
		// 						}	
		// 					})
		// 					.on('fail',function(data,response){
		// 						self.fail(data,response,req,res);
		// 						if(context.asyncMap){
		// 							context.callback(null, data);
		// 						}else{
		// 							context.callback(data,response);
		// 						}
		// 					});
		// 				}else{
		// 					context.data.accessToken=req.session.passport.user.token; 
		// 					rest[method](context.url,context.data)
		// 					.on('success',function(data,response){
		// 						delete self.restTasks[taskId]; 
		// 						if(context.asyncMap){
		// 							context.callback(null, data);
		// 						}else{
		// 							context.callback(data,response);
		// 						}	
		// 					})
		// 					.on('fail',function(data,response){
		// 						self.fail(data,response,req,res);
		// 						if(context.asyncMap){
		// 							context.callback(null, data);
		// 						}else{
		// 							context.callback(data,response);
		// 						}
		// 					});
		// 				} 
		// 			}else{
		// 				data = data||{};
		// 				data.redirect='/signIn';
		// 			}
		// 		}).on('fail',function(data,response){
		// 			data = data||{};
		// 			data.redirect='/signIn';
		// 	}); 
		// }
	},
	params: function (context, type) {
		var self = this;
		var tempData = context.params || {};
		var tempOptions = context.options || {};
		var tempHead = context.headers || {};
		var req = context.req, res = context.res;
		res.resultMsg = res.resultMsg || [];
		var ip = req.ip.match(/\d+\.\d+\.\d+\.\d+/)[0];
		tempHead['SXClientIP'] = ip;
		tempHead['Client-Ip'] = ip;
		var tempParams = {
			data: tempData,
			headers: tempHead,
			timeout: 1000 * 60 * 10
		};
		context.options.headers = tempHead;
		// self.logger.info('req.session.passport.user.token:',req.session.passport.user.token);
		if (type === 'json') {
			tempParams = context.params || {};
			tempOptions = context.options || {};
			if (!context.excludeToken) {
				tempOptions.accessToken = req.session.passport.user.token;
			}
			if (context.useUrl) {
				self.preLog(context.url, tempParams);
			} else {
				self.preLog(self.getUrl(context.url, context.baseUrl), tempParams);
			}
		} else {
			if (!context.excludeToken) {
				tempParams.accessToken = req.session.passport.user.token;
			}
			self.preLog(self.getUrl(context.url, context.baseUrl), tempData);
		}
		tempOptions['timeout'] = 1000 * 60 * 10;
		return {
			url: context.useUrl ? context.url : self.getUrl(context.url, context.baseUrl),
			data: tempParams,
			options: tempOptions,
			callback: context.callback,
			req: req,
			res: res
		};
	},
	addTask: function (type, context, data, response) {
		var self = this;
		var id = self.generateID();
		self.restTasks[id] = {
			'type': type,
			'context': context
		};
		// self.reflashToken(data,response,id);
	},
	generateID: function () {
		return uuid();
	},
	error: function (err, respones, req, res) {
		this.logger.info('this have a err! Maby connection aborted,parse,encoding,decoding failed or some other unhandled errors');
		this.logger.error(err);

	},
	fail: function (data, respones, req, res) {
		this.logger.info('request is fail!');
		this.logger.info(respones.statusCode);
		this.logger.error(data);
		res.resultMsg.push(data);
	}
};



exports = module.exports = function (logger, settings) {
	var helper = new RestHelper(logger, settings);
	function _getUrl(url, baseUrl) {
		return helper.getUrl(url, baseUrl);
	}

	function _preLog(tempUrl, tempParams) {
		helper.preLog(tempUrl, tempParams);
	}

	function _error(err, respones) {
		logger.info('this have a err! Maby connection aborted,parse,encoding,decoding failed or some other unhandled errors');
		logger.error(err);
		return
	}

	function _fail(data, respones) {
		logger.info('request is fail!');
		logger.info(respones.statusCode);
		logger.info(data);
		return
	}

	function restClient(options, success, fail) {
		var postData = !options.params ? '' : options.params;
		var httpRequest = http.request(options, function (res) {
			var _data = '';
			res.setEncoding('utf8');
			res.on('data', function (chunk) {
				_data += chunk;
			});
			res.on('end', function () {
				success(_data, res);
			});
		});
		httpRequest.on('error', function (e) {
			fail(e);
		});
		httpRequest.write(postData);
		httpRequest.end();
	}

	function get(context) {
		var param = helper.params(context);
		rest.get(param.url, param.data)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('get', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}

	function post(context) {
		var param = helper.params(context);
		rest.post(param.url, param.data)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('post', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}
	function put(context) {
		var param = helper.params(context);
		rest.put(param.url, param.data)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('put', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}
	function del(context) {
		var param = helper.params(context);
		if (param.data && param.data.data)
			param.data.data = JSON.stringify(param.data.data);
		rest.del(param.url, param.data)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('del', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}

	function patch(context) {
		var param = helper.params(context);
		rest.patch(param.url, param.data)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('patch', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}

	function json(context) {
		var param = helper.params(context, 'json');
		rest.json(param.url, param.data, param.options)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('json', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}
	function postJson(context) {
		var param = helper.params(context, 'json');
		rest.postJson(param.url, param.data, param.options)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('postJson', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}

	function register(context) {
		var param = helper.params(context, 'json');
		rest.postJson(param.url, param.data, param.options)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				_fail(data, response);
				context.callback(data, response);
			});
	}

	function putJson(context) {
		var param = helper.params(context, 'json');
		rest.putJson(param.url, param.data, param.options)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('putJson', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}

	function patchJson(context) {
		var param = helper.params(context, 'json');
		rest.patchJson(param.url, param.data, param.options)
			.on('success', context.callback)
			.on('fail', function (data, response) {
				if (response.statusCode === 401) {
					helper.addTask('patchJson', param, data, response);
				} else {
					_fail(data, response);
					context.callback(data, response);
				}
			});
	}

	function asyncMap(contexts, cb) {
		var AsyncLibrary = {
			sendRequest: function (number, callback) {
				var context = number;
				var tempParams = context.params || {};
				var tempOptions = context.options || {};
				var req = context.req, res = context.res;
				res.resultMsg = res.resultMsg || [];
				if (!context.excludeToken) {
					tempOptions.accessToken = req.session.passport.user.token;
				}
				_preLog(_getUrl(context.url, context.baseUrl), tempParams);
				rest[context.method](_getUrl(context.url, context.baseUrl), tempParams, tempOptions)
					.on('success', function (data, response) {
						callback(null, data);
					})
					.on('fail', function (data, response) {
						if (response.statusCode === 401) {
							var param = helper.params(context, 'json');
							param.callback = callback;
							param.asyncMap = true;
							helper.addTask(context.method, param, data, response);
						} else {
							callback(null, data);
						}
					});
			}
		};
		async.map(contexts, AsyncLibrary.sendRequest, cb);
	}

	function transformParams(jsonParams) {
		var params = ['?'];
		for (var i in jsonParams) {
			params.push(i + '=' + jsonParams[i] + '&');
		}
		return params.join('').substring(0, params.join('').length - 1);
	}

	function getFormFields(context) {
		return restq.get(helper.getUrl(context.url, context.baseUrl), {
			accessToken: context.params.token
		})
	}

	function initOssToken(context) {
		return restq.postJson(helper.getUrl(context.url, context.baseUrl), context.params, {
			accessToken: context.options.token
		});
	}

	return {
		get: get,
		post: post,
		put: put,
		del: del,
		patch: patch,
		json: json,
		postJson: postJson,
		putJson: putJson,
		patchJson: patchJson,
		transformParams: transformParams,
		register: register,
		restful: rest,
		getBaseUrl: _getUrl,
		map: asyncMap,
		getFormFields: getFormFields,
		initOssToken: initOssToken,
		restClient: restClient
	};
};




exports['@singleton'] = true;
exports['@require'] = ['igloo/logger', 'igloo/settings'];