text: import debug from 'debug';
  import { check } from 'express-validator';
  
  import { ifNoUser401, createValidatorErrorHandler } from '../utils/middleware';
  import { themes } from '../../common/utils/themes.js';
  import { alertTypes } from '../../common/utils/flash.js';
  import { isValidUsername } from '../../../utils/validate';
  
  const log = debug('fcc:boot:settings');
  
  export default function settingsController(app) {
    const api = app.loopback.Router();
  
    const updateMyUsername = createUpdateMyUsername(app);
  
    api.put('/update-privacy-terms', ifNoUser401, updatePrivacyTerms);
  
    api.post(
      '/refetch-user-completed-challenges',
      ifNoUser401,
      refetchCompletedChallenges
    );
    api.post(
      '/update-my-current-challenge',
      ifNoUser401,
      updateMyCurrentChallengeValidators,
      createValidatorErrorHandler(alertTypes.danger),
      updateMyCurrentChallenge
    );
    api.post('/update-my-portfolio', ifNoUser401, updateMyPortfolio);
    api.post('/update-my-projects', ifNoUser401, updateMyProjects);
    api.post(
      '/update-my-theme',
      ifNoUser401,
      updateMyThemeValidators,
      createValidatorErrorHandler(alertTypes.danger),
      updateMyTheme
    );
    api.put('/update-my-about', ifNoUser401, updateMyAbout);
    api.put(
      '/update-my-email',
      ifNoUser401,
      updateMyEmailValidators,
      createValidatorErrorHandler(alertTypes.danger),
      updateMyEmail
    );
    api.put('/update-my-profileui', ifNoUser401, updateMyProfileUI);
    api.put('/update-my-username', ifNoUser401, updateMyUsername);
    api.put('/update-user-flag', ifNoUser401, updateUserFlag);
  
    app.use(api);
  }
  
  const standardErrorMessage = {
    type: 'danger',
    message:
      'Something went wrong updating your account. Please check and try again'
  };
  
  const standardSuccessMessage = {
    type: 'success',
    message: 'We have updated your preferences'
  };
  
  const createStandardHandler = (req, res, next) => err => {
    if (err) {
      res.status(500).json(standardErrorMessage);
      return next(err);
    }
    return res.status(200).json(standardSuccessMessage);
  };
  
  function refetchCompletedChallenges(req, res, next) {
    const { user } = req;
    return user
      .requestCompletedChallenges()
      .subscribe(completedChallenges => res.json({ completedChallenges }), next);
  }
  
  const updateMyEmailValidators = [
    check('email')
      .isEmail()
      .withMessage('Email format is invalid.')
  ];
  
  function updateMyEmail(req, res, next) {
    const {
      user,
      body: { email }
    } = req;
    return user
      .requestUpdateEmail(email)
      .subscribe(message => res.json({ message }), next);
  }
  
  const updateMyCurrentChallengeValidators = [
    check('currentChallengeId')
      .isMongoId()
      .withMessage('currentChallengeId is not a valid challenge ID')
  ];
  
  function updateMyCurrentChallenge(req, res, next) {
    const {
      user,
      body: { currentChallengeId }
    } = req;
    return user.updateAttribute(
      'currentChallengeId',
      currentChallengeId,
      (err, updatedUser) => {
        if (err) {
          return next(err);
        }
        const { currentChallengeId } = updatedUser;
        return res.status(200).json(currentChallengeId);
      }
    );
  }
  
  const updateMyThemeValidators = [
    check('theme')
      .isIn(Object.keys(themes))
      .withMessage('Theme is invalid.')
  ];
  
  function updateMyTheme(req, res, next) {
    const {
      body: { theme }
    } = req;
    if (req.user.theme === theme) {
      return res.sendFlash(alertTypes.info, 'Theme already set');
    }
    return req.user
      .updateTheme(theme)
      .then(
        () => res.sendFlash(alertTypes.info, 'Your theme has been updated!'),
        next
      );
  }
  
  function updateMyPortfolio(req, res, next) {
    const {
      user,
      body: { portfolio }
    } = req;
    // if we only have one key, it should be the id
    // user cannot send only one key to this route
    // other than to remove a portfolio item
    const requestDelete = Object.keys(portfolio).length === 1;
    return user
      .updateMyPortfolio(portfolio, requestDelete)
      .subscribe(message => res.json({ message }), next);
  }
  
  function updateMyProfileUI(req, res, next) {
    const {
      user,
      body: { profileUI }
    } = req;
    user.updateAttribute(
      'profileUI',
      profileUI,
      createStandardHandler(req, res, next)
    );
  }
  
  function updateMyProjects(req, res, next) {
    const {
      user,
      body: { projects: project }
    } = req;
    return user
      .updateMyProjects(project)
      .subscribe(message => res.json({ message }), next);
  }
  
  function updateMyAbout(req, res, next) {
    const {
      user,
      body: { name, location, about, picture }
    } = req;
    log(name, location, picture, about);
    return user.updateAttributes(
      { name, location, about, picture },
      createStandardHandler(req, res, next)
    );
  }
  
  function createUpdateMyUsername(app) {
    const { User } = app.models;
    return async function updateMyUsername(req, res, next) {
      const {
        user,
        body: { username }
      } = req;
      if (username === user.username) {
        return res.json({
          type: 'info',
          message: 'Username is already associated with this account'
        });
      }
      const validation = isValidUsername(username);
  
      if (!validation.valid) {
        return res.json({
          type: 'info',
          message: `Username ${username} ${validation.error}`
        });
      }
  
      const exists = await User.doesExist(username);
  
      if (exists) {
        return res.json({
          type: 'info',
          message: 'Username is already associated with a different account'
        });
      }
  
      return user.updateAttribute('username', username, err => {
        if (err) {
          res.status(500).json(standardErrorMessage);
          return next(err);
        }
        return res.status(200).json({
          type: 'success',
          message: `We have updated your username to ${username}`
        });
      });
    };
  }
  
  const updatePrivacyTerms = (req, res, next) => {
    const {
      user,
      body: { quincyEmails }
    } = req;
    const update = {
      acceptedPrivacyTerms: true,
      sendQuincyEmail: !!quincyEmails
    };
    return user.updateAttributes(update, err => {
      if (err) {
        res.status(500).json(standardErrorMessage);
        return next(err);
      }
      return res.status(200).json({
        type: 'success',
        message: `We have updated your preferences.`
      });
    });
  };
  
  function updateUserFlag(req, res, next) {
    const { user, body: update } = req;
    return user.updateAttributes(update, createStandardHandler(req, res, next));
  }
  