text: const crypto = require('crypto')
  const Sequelize = require('sequelize')
  const db = require('../db')
  
  const User = db.define('user', {
    email: {
      type: Sequelize.STRING,
      unique: true,
      validate: {
        isEmail: true
      }
    },
    password: {
      type: Sequelize.STRING,
      // Making `.password` act like a func hides it when serializing to JSON.
      // This is a hack to get around Sequelize's lack of a "private" option.
      get() {
        return () => this.getDataValue('password')
      }
    },
    salt: {
      type: Sequelize.STRING,
      // Making `.salt` act like a function hides it when serializing to JSON.
      // This is a hack to get around Sequelize's lack of a "private" option.
      get() {
        return () => this.getDataValue('salt')
      }
    },
    googleId: {
      type: Sequelize.STRING
    },
    firstName: {
      type: Sequelize.STRING
    },
    lastName: {
      type: Sequelize.STRING
    },
    address: {
      type: Sequelize.STRING
    },
    address2: {
      type: Sequelize.STRING
    },
    city: {
      type: Sequelize.STRING
    },
    state: {
      type: Sequelize.STRING
    },
    zip: {
      type: Sequelize.STRING
    },
    picture: {
      type: Sequelize.STRING
    },
    isAdmin: {
      type: Sequelize.BOOLEAN,
      defaultValue: false
    },
    sessionId: {
      type: Sequelize.STRING
    }
  })
  
  module.exports = User
  
  /**
   * instanceMethods
   */
  User.prototype.correctPassword = function(candidatePwd) {
    return User.encryptPassword(candidatePwd, this.salt()) === this.password()
  }
  
  /**
   * classMethods
   */
  User.generateSalt = function() {
    return crypto.randomBytes(16).toString('base64')
  }
  
  User.encryptPassword = function(plainText, salt) {
    return crypto
      .createHash('RSA-SHA256')
      .update(plainText)
      .update(salt)
      .digest('hex')
  }
  
  User.findUserBySession = async function(sessionId) {
    const guestUser = await User.findOne({
      where: {
        sessionId: sessionId
      }
    })
  
    if (guestUser) {
      return guestUser.id
    }
  
    return undefined
  }
  
  User.findOrCreateUserBySession = async function(sessionId) {
    const guestUser = await User.findUserBySession(sessionId)
    if (guestUser) {
      return guestUser
    } else {
      // create a user containing the session identifier...
      const newUser = await User.create({
        sessionId: sessionId
      })
      if (newUser) {
        //console.log('successfully created new user with session: ', newUser)
        return newUser.id
      }
    }
  
    return undefined
  }
  
  User.findAllUsers = function() {
    return User.findAll({
      attributes: [
        'id',
        'email',
        'address',
        'address2',
        'city',
        'state',
        'zip',
        'firstName',
        'lastName',
        'isAdmin'
      ],
      order: Sequelize.col('id')
    })
  }
  
  /**
   * hooks
   */
  const setSaltAndPassword = user => {
    if (user.changed('password')) {
      user.salt = User.generateSalt()
      user.password = User.encryptPassword(user.password(), user.salt())
    }
  }
  
  User.beforeCreate(setSaltAndPassword)
  User.beforeUpdate(setSaltAndPassword)
  User.beforeBulkCreate(users => {
    users.forEach(setSaltAndPassword)
  })
  