'use strict';

// public api
var user = {
  getAccountPropertyStats: function(req, res, next) {
    var counts = {};
    var statuses = ['PropertySubmitted', 'New', 'ActivelyWorking', 'OfferAccepted', 'OfferRejected', 'UCSeller', 'UCBuyer', 'Closed','DeadLeads'];
    var queries = [];
    statuses.forEach(function(status, i, arr){
      queries.push(function(done){
        switch (status){
        case 'PropertySubmitted':
          req.app.db.models.Property.find({ "user.id" : req.params.id }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'New':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status" : 'new' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'ActivelyWorking':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status": 'inProgress' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'OfferAccepted':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status": 'offerAccepted' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'OfferRejected':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status": 'offerRejected' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'UCSeller':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status": 'ucSeller' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'UCBuyer':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status": 'ucBuyer' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'Closed':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status": 'closed' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;
        case 'DeadLeads':
          req.app.db.models.Property.find({ "user.id" : req.params.id, "status": 'deadLeads' }).count({}, function(err, count){
            if(err){
              return done(err);
            }
            counts[status] = count;
            done();
          });
          break;

        }
        
      });
    });   
    var asyncFinally = function(err, results){
      if(err){
        return next(err);
      }
      res.status(200).json(counts);
    };

    require('async').parallel(queries, asyncFinally);    
  },
  find: function (req, res, next) {
    req.query.username = req.query.username ? req.query.username : '';
    req.query.limit = req.query.limit ? parseInt(req.query.limit, null) : 20;
    req.query.page = req.query.page ? parseInt(req.query.page, null) : 1;
    req.query.sort = req.query.sort ? req.query.sort : '_id';
    req.query.isActive = req.query.isActive ? req.query.isActive : '';
    req.query.roles = req.query.roles ? req.query.roles : '';

    var filters = {};
    if (req.query.username) {
      filters.username = new RegExp('^.*?' + req.query.username + '.*$', 'i');
    }

    if (req.query.isActive) {
      filters.isActive = req.query.isActive;
    }

    if (req.query.roles && req.query.roles === 'admin') {
      filters['roles.admin'] = {$exists: true};
    }

    if (req.query.roles && req.query.roles === 'account') {
      filters['roles.account'] = {$exists: true};
    }
    req.app.db.models.User.pagedFind({

      filters: filters,
      keys: 'username email isActive timeCreated roles badge status photoURL',
      limit: req.query.limit,
      page: req.query.page,
      sort: req.query.sort
    }, function (err, results) {
      if (err) {
        return next(err);
      }
      results.filters = req.query;
      res.status(200).json(results);
    });
  },

  create: function (req, res, next) {
    var workflow = req.app.utility.workflow(req, res);
    workflow.on('validate', function () {
      if (!req.body.username) {
        workflow.outcome.errors.push('Please enter a username.');
        return workflow.emit('response');
      }

      if (!/^[a-zA-Z0-9\-\_]+$/.test(req.body.username)) {
        workflow.outcome.errors.push('only use letters, numbers, -, _');
        return workflow.emit('response');
      }

      workflow.emit('duplicateUsernameCheck');
    });

    workflow.on('duplicateUsernameCheck', function () {
      req.app.db.models.User.findOne({username: req.body.username}, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errors.push('That username is already taken.');
          return workflow.emit('response');
        }

        workflow.emit('createUser');
      });
    });

    workflow.on('createUser', function () {
      var fieldsToSet = {
        username: req.body.username,
        search: [
          req.body.username
        ]
      };
      req.app.db.models.User.create(fieldsToSet, function (err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.outcome.record = user;
        return workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },

  read: function(req, res, next){
    req.app.db.models.User.findById(req.params.id).populate('roles.admin', 'name.full').populate('roles.account', 'name.full').exec(function(err, user) {
      if (err) {
        return next(err);
      }
      res.status(200).json(user);
    });
  },

  update: function(req, res, next){
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function() {
      if (!req.body.isActive) {
        req.body.isActive = 'no';
      }

      if (!req.body.username) {
        workflow.outcome.errfor.username = 'required';
      }
      else if (!/^[a-zA-Z0-9\-\_]+$/.test(req.body.username)) {
        workflow.outcome.errfor.username = 'only use letters, numbers, \'-\', \'_\'';
      }

      if (!req.body.email) {
        workflow.outcome.errfor.email = 'required';
      }
      else if (!/^[a-zA-Z0-9\-\_\.\+]+@[a-zA-Z0-9\-\_\.]+\.[a-zA-Z0-9\-\_]+$/.test(req.body.email)) {
        workflow.outcome.errfor.email = 'invalid email format';
      }

      if (workflow.hasErrors()) {
        return workflow.emit('response');
      }

      workflow.emit('duplicateUsernameCheck');
    });

    workflow.on('duplicateUsernameCheck', function() {
      req.app.db.models.User.findOne({ username: req.body.username, _id: { $ne: req.params.id } }, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errfor.username = 'username already taken';
          return workflow.emit('response');
        }

        workflow.emit('duplicateEmailCheck');
      });
    });

    workflow.on('duplicateEmailCheck', function() {
      req.app.db.models.User.findOne({ email: req.body.email.toLowerCase(), _id: { $ne: req.params.id } }, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errfor.email = 'email already taken';
          return workflow.emit('response');
        }

        workflow.emit('patchUser');
      });
    });

    workflow.on('patchUser', function() {
      var fieldsToSet = {
        isActive: req.body.isActive,
        username: req.body.username,
        email: req.body.email.toLowerCase(),
        search: [
          req.body.username,
          req.body.email
        ]
      };
      var options = { new: true }; //so that user returned is the updated not original doc

      req.app.db.models.User.findByIdAndUpdate(req.params.id, fieldsToSet, options, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }
        workflow.emit('patchAdmin', user);
      });
    });

    workflow.on('patchAdmin', function(user) {
      if (user.roles.admin) {
        var fieldsToSet = {
          user: {
            id: req.params.id,
            name: user.username
          }
        };
        req.app.db.models.Admin.findByIdAndUpdate(user.roles.admin, fieldsToSet, function(err, admin) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('patchAccount', user);
        });
      }
      else {
        workflow.emit('patchAccount', user);
      }
    });

    workflow.on('patchAccount', function(user) {
      if (user.roles.account) {
        var fieldsToSet = {
          user: {
            id: req.params.id,
            name: user.username
          }
        };
        req.app.db.models.Account.findByIdAndUpdate(user.roles.account, fieldsToSet, function(err, account) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('populateRoles', user);
        });
      }
      else {
        workflow.emit('populateRoles', user);
      }
    });

    workflow.on('populateRoles', function(user) {
      user.populate('roles.admin roles.account', 'name.full', function(err, populatedUser) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.outcome.user = populatedUser;
        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },

  password: function(req, res, next){
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function() {
      if (!req.body.newPassword) {
        workflow.outcome.errfor.newPassword = 'required';
      }

      if (!req.body.confirm) {
        workflow.outcome.errfor.confirm = 'required';
      }

      if (req.body.newPassword !== req.body.confirm) {
        workflow.outcome.errors.push('Passwords do not match.');
      }

      if (workflow.hasErrors()) {
        return workflow.emit('response');
      }

      workflow.emit('patchUser');
    });

    workflow.on('patchUser', function() {
      req.app.db.models.User.encryptPassword(req.body.newPassword, function(err, hash) {
        if (err) {
          return workflow.emit('exception', err);
        }

        var fieldsToSet = { password: hash };
        var options = { new: true };
        req.app.db.models.User.findByIdAndUpdate(req.params.id, fieldsToSet, options, function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function(err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.outcome.newPassword = '';
            workflow.outcome.confirm = '';
            workflow.emit('response');
          });
        });
      });
    });

    workflow.emit('validate');
  },

  linkAdmin: function(req, res, next){
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function() {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not link users to admins.');
        return workflow.emit('response');
      }

      if (!req.body.newAdminId) {
        workflow.outcome.errfor.newAdminId = 'required';
        return workflow.emit('response');
      }

      workflow.emit('verifyAdmin');
    });

    workflow.on('verifyAdmin', function(callback) {
      req.app.db.models.Admin.findById(req.body.newAdminId).exec(function(err, admin) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!admin) {
          workflow.outcome.errors.push('Admin not found.');
          return workflow.emit('response');
        }

        if (admin.user.id && admin.user.id !== req.params.id) {
          workflow.outcome.errors.push('Admin is already linked to a different user.');
          return workflow.emit('response');
        }

        workflow.admin = admin;
        workflow.emit('duplicateLinkCheck');
      });
    });

    workflow.on('duplicateLinkCheck', function(callback) {
      req.app.db.models.User.findOne({ 'roles.admin': req.body.newAdminId, _id: {$ne: req.params.id} }).exec(function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errors.push('Another user is already linked to that admin.');
          return workflow.emit('response');
        }

        workflow.emit('patchUser');
      });
    });

    workflow.on('patchUser', function(callback) {
      req.app.db.models.User.findById(req.params.id).exec(function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        user.roles.admin = req.body.newAdminId;
        user.save(function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function(err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAdmin');
          });
        });
      });
    });

    workflow.on('patchAdmin', function() {
      workflow.admin.user = { id: req.params.id, name: workflow.outcome.user.username };
      workflow.admin.save(function(err, admin) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },

  unlinkAdmin: function(req, res, next){
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function() {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not unlink users from admins.');
        return workflow.emit('response');
      }

      if (req.user._id + '' === req.params.id) {
        workflow.outcome.errors.push('You may not unlink yourself from admin.');
        return workflow.emit('response');
      }

      workflow.emit('patchUser');
    });

    workflow.on('patchUser', function() {
      req.app.db.models.User.findById(req.params.id).exec(function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!user) {
          workflow.outcome.errors.push('User was not found.');
          return workflow.emit('response');
        }

        var adminId = user.roles.admin;
        user.roles.admin = null;
        user.save(function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function(err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAdmin', adminId);
          });
        });
      });
    });

    workflow.on('patchAdmin', function(id) {
      req.app.db.models.Admin.findById(id).exec(function(err, admin) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!admin) {
          workflow.outcome.errors.push('Admin was not found.');
          return workflow.emit('response');
        }

        admin.user = undefined;
        admin.save(function(err, admin) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('response');
        });
      });
    });

    workflow.emit('validate');
  },

  linkAccount: function(req, res, next){
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function() {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not link users to accounts.');
        return workflow.emit('response');
      }

      if (!req.body.newAccountId) {
        workflow.outcome.errfor.newAccountId = 'required';
        return workflow.emit('response');
      }

      workflow.emit('verifyAccount');
    });

    workflow.on('verifyAccount', function(callback) {
      req.app.db.models.Account.findById(req.body.newAccountId).exec(function(err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!account) {
          workflow.outcome.errors.push('Account not found.');
          return workflow.emit('response');
        }

        if (account.user.id && account.user.id !== req.params.id) {
          workflow.outcome.errors.push('Account is already linked to a different user.');
          return workflow.emit('response');
        }

        workflow.account = account;
        workflow.emit('duplicateLinkCheck');
      });
    });

    workflow.on('duplicateLinkCheck', function(callback) {
      req.app.db.models.User.findOne({ 'roles.account': req.body.newAccountId, _id: {$ne: req.params.id} }).exec(function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (user) {
          workflow.outcome.errors.push('Another user is already linked to that account.');
          return workflow.emit('response');
        }

        workflow.emit('patchUser');
      });
    });

    workflow.on('patchUser', function(callback) {
      req.app.db.models.User.findById(req.params.id).exec(function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        user.roles.account = req.body.newAccountId;
        user.save(function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function(err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAccount');
          });
        });
      });
    });

    workflow.on('patchAccount', function() {
      workflow.account.user = { id: req.params.id, name: workflow.outcome.user.username };
      workflow.account.save(function(err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },

  unlinkAccount: function(req, res, next){
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function() {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not unlink users from accounts.');
        return workflow.emit('response');
      }

      workflow.emit('patchUser');
    });

    workflow.on('patchUser', function() {
      req.app.db.models.User.findById(req.params.id).exec(function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!user) {
          workflow.outcome.errors.push('User was not found.');
          return workflow.emit('response');
        }

        var accountId = user.roles.account;
        user.roles.account = null;
        user.save(function(err, user) {
          if (err) {
            return workflow.emit('exception', err);
          }

          user.populate('roles.admin roles.account', 'name.full', function(err, user) {
            if (err) {
              return workflow.emit('exception', err);
            }

            workflow.outcome.user = user;
            workflow.emit('patchAccount', accountId);
          });
        });
      });
    });

    workflow.on('patchAccount', function(id) {
      req.app.db.models.Account.findById(id).exec(function(err, account) {
        if (err) {
          return workflow.emit('exception', err);
        }

        if (!account) {
          workflow.outcome.errors.push('Account was not found.');
          return workflow.emit('response');
        }

        account.user = undefined;
        account.save(function(err, account) {
          if (err) {
            return workflow.emit('exception', err);
          }

          workflow.emit('response');
        });
      });
    });

    workflow.emit('validate');
  },

  strikeUser: function(req, res, next) {
    var workflow = req.app.utility.workflow(req, res);
    workflow.on('patchProbationStrike', function() {
      req.app.db.models.User.findById(req.params.id).exec(function(err, result){
        if (result.probationStrike < 3){
          req.app.db.models.User.findByIdAndUpdate(req.params.id, {"probationStrike": result.probationStrike + 1}, function(err, strike){
          });    
        }
      });
      workflow.emit('makeNonActive');
    });
    workflow.on('makeNonActive', function() {
      req.app.db.models.User.findById(req.params.id).exec(function(err, result){
        if (result.probationStrike == 3) {
          req.app.db.models.User.findByIdAndUpdate(req.params.id, {"isActive": 'no'}, function(err, strike){
          });
        }
      });
      workflow.emit('response');
    });
    workflow.emit('patchProbationStrike');    
  },
  delete: function(req, res, next){
    var workflow = req.app.utility.workflow(req, res);

    workflow.on('validate', function() {
      if (!req.user.roles.admin.isMemberOf('root')) {
        workflow.outcome.errors.push('You may not delete users.');
        return workflow.emit('response');
      }

      // work around as typeof req.user._id === "Object"
      if (req.user._id + '' === req.params.id) {
        workflow.outcome.errors.push('You may not delete yourself from user.');
        return workflow.emit('response');
      }

      workflow.emit('deleteUser');
    });

    workflow.on('deleteUser', function(err) {
      req.app.db.models.User.findByIdAndRemove(req.params.id, function(err, user) {
        if (err) {
          return workflow.emit('exception', err);
        }

        workflow.emit('response');
      });
    });

    workflow.emit('validate');
  },

  getSubmittedProperties: function(req, res, next) {
    req.app.db.models.Property.find({ "user.id" : req.params.id }).exec(function(err, property) {
      if (err) {
        return next(err);
      }
      res.status(200).json(property);
      
    });
  } 
};
module.exports = user;