# Source: controller/passport_controller.js

    'use strict';

    var logger,
    	User,
    	passport,
    	loginExtSettings,
    	merge = require('utils-merge'),
    	FacebookStrategy = require('passport-facebook').Strategy,
    	InstagramStrategy = require('passport-instagram').Strategy,
    	TwitterStrategy = require('passport-twitter').Strategy,
    	LocalStrategy = require('passport-local').Strategy;

    var linkSocialAccount = function (options) {
    	var done = options.donecallback,
    		findsocialaccountquery = options.findsocialaccountquery,
    		socialaccountattributes = options.socialaccountattributes,
    		newaccountdata = options.newaccountdata,
    		linkaccountservice = options.linkaccountservice,
    		requestobj = options.requestobj;
    	User.findOne(findsocialaccountquery,
    		function (err, existingUser) {
    			if (err) {
    				return done(err);
    			}
    			else if (existingUser) {
    				logger.info('ext - controller/auth.js - already has an account, trying to connect account');
    				existingUser.attributes = merge(existingUser.attributes, socialaccountattributes);
    				existingUser.save(done);
    			}
    			else if (requestobj.user) {
    				requestobj.session.linkaccount = true;
    				requestobj.session.linkaccountservice = 'instagram';
    				requestobj.session.linkaccountdata = socialaccountattributes;
    				done(null, requestobj.user);
    			}
    			else {
    				logger.info('ext - controller/auth.js - creating new ' + linkaccountservice + ' user');
    				newaccountdata.attributes = socialaccountattributes;
    				User.create(newaccountdata, done);
    			}
    		});
    };

    var authenticateUser = function (options) {
    	var username = options.username,
    		donecallback = options.done,
    		nonusercallback = options.nonusercallback,
    		existinusercallback = options.existinusercallback,
    		exitinguserquery = options.exitinguserquery;
    	User.findOne(exitinguserquery, function (err, user) {
    		if (err) {
    			logger.silly('login error');
    			donecallback(err);
    		}
    		else if (!user) {
    			logger.silly('login no user');
    			nonusercallback();
    		}
    		else {
    			logger.silly('login found exiting user');
    			existinusercallback(user);
    		}
    	});
    };

    /**
     * uses passport to log users in, calls done(err,user) when complete, can define what credentials to check here
     * @param  {object} req
     * @param  {object} res
     * @return {Function} done(err,user) callback
     */
    var usePassport = function () {
    	passport.use(new LocalStrategy(function (username, password, done) {
    		authenticateUser({
    			exitinguserquery: {
    				$or: [{
    					username: {
    						$regex: new RegExp(username, 'i')
    					}
    				}, {
    					email: {
    						$regex: new RegExp(username, 'i')
    					}
    				}]
    			},
    			nonusercallback: function () {
    				done(null, false, {
    					message: 'Unknown user ' + username
    				});
    			},
    			existinusercallback: function (user) {
    				if (loginExtSettings && loginExtSettings.settings.usepassword === false) {
    					logger.verbose(' skip password usage ');
    					done(null, user);
    				}
    				else {
    					user.comparePassword(password, function (err, isMatch) {
    						if (err) {
    							return done(err);
    						}

    						if (isMatch) {
    							return done(null, user);
    						}
    						else {
    							logger.verbose(' in passport callback when no password');
    							return done(null, false, {
    								message: 'Invalid password'
    							});
    						}
    					});
    				}
    			},
    			donecallback: done
    		});
    	}));

    	if (loginExtSettings && loginExtSettings.passport && loginExtSettings.passport.oauth.facebook && loginExtSettings.passport.oauth.facebook.appid) {
    		passport.use(new FacebookStrategy({
    				clientID: loginExtSettings.passport.oauth.facebook.appid,
    				clientSecret: loginExtSettings.passport.oauth.facebook.appsecret,
    				callbackURL: loginExtSettings.passport.oauth.facebook.callbackurl,
    				passReqToCallback: true
    			},
    			function (req, accessToken, refreshToken, profile, done) {
    				var facebookdata = profile._json;

    				authenticateUser({
    					exitinguserquery: {
    						email: facebookdata.email,
    						'attributes.facebookid': facebookdata.id,
    						'attributes.facebookaccesstoken': accessToken.toString()
    					},
    					existinusercallback: function (user) {
    						return done(null, user);
    					},
    					nonusercallback: function () {
    						linkSocialAccount({
    							donecallback: done,
    							linkaccountservice: 'facebook',
    							requestobj: req,
    							findsocialaccountquery: {
    								email: facebookdata.email,
    								'attributes.facebookid': facebookdata.id
    							},
    							socialaccountattributes: {
    								facebookid: facebookdata.id,
    								facebookaccesstoken: accessToken,
    								facebookusername: facebookdata.username,
    								facebookaccesstokenupdated: new Date()
    							},
    							newaccountdata: {
    								email: facebookdata.email,
    								activated: true,
    								accounttype: 'social-sign-in',
    								firstname: facebookdata.first_name,
    								lastname: facebookdata.last_name
    							}
    						});
    					},
    					donecallback: done
    				});
    			}));
    	}

    	if (loginExtSettings && loginExtSettings.passport && loginExtSettings.passport.oauth.instagram && loginExtSettings.passport.oauth.instagram.clientid) {
    		passport.use(new InstagramStrategy({
    				clientID: loginExtSettings.passport.oauth.instagram.clientid,
    				clientSecret: loginExtSettings.passport.oauth.instagram.clientsecret,
    				callbackURL: loginExtSettings.passport.oauth.instagram.callbackurl,
    				passReqToCallback: true,
    			},
    			function (req, accessToken, refreshToken, profile, done) {
    				// console.log('instagram req:',req); 	// console.log('instagram accessToken:',accessToken); // console.log('instagram refreshToken:',refreshToken); // console.log('instagram profile:',profile);

    				var instagramdata = profile;
    				authenticateUser({
    					exitinguserquery: {
    						// email: instagramdata.email,
    						'attributes.instagramid': instagramdata.id,
    						'attributes.instagramaccesstoken': accessToken.toString()
    					},
    					existinusercallback: function (user) {
    						console.log('user from instagram passport', user);
    						return done(null, user);
    					},
    					nonusercallback: function () {
    						linkSocialAccount({
    							donecallback: done,
    							linkaccountservice: 'instagram',
    							requestobj: req,
    							findsocialaccountquery: {
    								'attributes.instagramid': instagramdata.id,
    							},
    							socialaccountattributes: {
    								instagramid: instagramdata.id,
    								instagramaccesstoken: accessToken,
    								instagramusername: instagramdata.username,
    								instagramaccesstokenupdated: new Date()
    							},
    							newaccountdata: {
    								email: instagramdata.username + '@instagram.account.com',
    								username: instagramdata.username,
    								activated: true,
    								accounttype: 'social-sign-in',
    								firstname: instagramdata.first_name,
    								lastname: instagramdata.last_name
    							}
    						});
    					},
    					donecallback: done
    				});
    			}));

    	}

    	if (loginExtSettings && loginExtSettings.passport && loginExtSettings.passport.oauth.twitter && loginExtSettings.passport.oauth.twitter.consumerKey) {
    		passport.use(new TwitterStrategy({
    				consumerKey: loginExtSettings.passport.oauth.twitter.consumerKey,
    				consumerSecret: loginExtSettings.passport.oauth.twitter.consumerSecret,
    				callbackURL: loginExtSettings.passport.oauth.twitter.callbackurl,
    				passReqToCallback: true,
    			},
    			function (req, token, tokenSecret, profile, done) {
    				// console.log('twitter req:',req); 	// console.log('twitter accessToken:',accessToken); // console.log('twitter refreshToken:',refreshToken);
    				// console.log('twitter profile:', profile);

    				var twitterdata = profile;
    				authenticateUser({
    					exitinguserquery: {
    						// email: twitterdata.email,
    						'attributes.twitterid': twitterdata.id,
    						'attributes.twitteraccesstoken': token.toString(),
    						'attributes.twitteraccesstokensecret': tokenSecret.toString()
    					},
    					existinusercallback: function (user) {
    						console.log('user from twitter passport', user);
    						return done(null, user);
    					},
    					nonusercallback: function () {
    						linkSocialAccount({
    							donecallback: done,
    							linkaccountservice: 'twitter',
    							requestobj: req,
    							findsocialaccountquery: {
    								'attributes.twitterid': twitterdata.id
    							},
    							socialaccountattributes: {
    								twitterid: twitterdata.id,
    								twitterusername: twitterdata.username,
    								twitteraccesstoken: token,
    								twitteraccesstokensecret: tokenSecret,
    								twitteraccesstokenupdated: new Date()
    							},
    							newaccountdata: {
    								email: twitterdata.username + '@twitter.account.com',
    								username: twitterdata.username,
    								activated: true,
    								accounttype: 'social-sign-in',
    								firstname: twitterdata.name,
    							}
    						});
    					},
    					donecallback: done
    				});
    			}));
    	}
    };

    var serialize = function () {
    	/**
    	 * store user id in session
    	 * @param  {object} req
    	 * @param  {object} res
    	 * @return {Function} next() callback
    	 */
    	passport.serializeUser(function (user, done) {
    		logger.verbose('controller - auth.js - serialize user');
    		done(null, user._id);
    	});
    };

    var deserialize = function () {
    	/**
    	 * retrieves user data
    	 * @param  {object} req
    	 * @param  {object} res
    	 * @return {Function} next() callback
    	 */
    	passport.deserializeUser(function (token, done) {
    		logger.verbose('controller - auth.js - deserialize user');
    		User.findOne({
    				_id: token
    			})
    			.populate('userroles primaryasset')
    			.exec(function (err, user) {
    				done(err, user);
    			});
    	});
    };
    var passportController = function (resources, passportResources) {
    	logger = resources.logger;
    	User = passportResources.User;
    	passport = passportResources.passport;
    	loginExtSettings = passportResources.loginExtSettings;
    	return {
    		usePassport: usePassport,
    		deserialize: deserialize,
    		serialize: serialize,
    		passport: passport
    	};
    };

    module.exports = passportController;