import { check } from 'express-validator/check';

import {
  ifNoUser401,
  createValidatorErrorHandler
} from '../utils/middleware';
import supportedLanguages from '../../common/utils/supported-languages.js';
import { themes } from '../../common/utils/themes.js';
import { alertTypes } from '../../common/utils/flash.js';

export default function settingsController(app) {
  const api = app.loopback.Router();
  const toggleUserFlag = (flag, req, res, next) => {
    const { user } = req;
    const currentValue = user[ flag ];
    return user
      .update$({ [ flag ]: !currentValue })
      .subscribe(
        () => res.status(200).json({
          flag,
          value: !currentValue
        }),
        next
      );
  };

  function refetchChallengeMap(req, res, next) {
    const { user } = req;
    return user.requestChallengeMap()
      .subscribe(
        challengeMap => res.json({ challengeMap }),
        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.sendFlash(alertTypes.info, message),
        next
      );
  }

  function updateMyLang(req, res, next) {
    const { user, body: { lang } = {} } = req;
    const langName = supportedLanguages[lang];
    const update = { languageTag: lang };
    if (!supportedLanguages[lang]) {
      return res.json({
        message: `${lang} is currently unsupported`
      });
    }
    if (user.languageTag === lang) {
      return res.json({
        message: `Your language is already set to ${langName}`
      });
    }
    return user.update$(update)
      .subscribe(
        () => res.json({
          message: `Your language has been updated to '${langName}'`
        }),
        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.update$({ currentChallengeId }).subscribe(
      () => res.json({
        message:
          `your current challenge has been updated to ${currentChallengeId}`
      }),
      next
    );
  }

  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 updateFlags(req, res, next) {
    const { user, body: { values } } = req;
    const keys = Object.keys(values);
    if (
      keys.length === 1 &&
      typeof keys[0] === 'boolean'
    ) {
      return toggleUserFlag(keys[0], req, res, next);
    }
    return user.requestUpdateFlags(values)
      .subscribe(
        message => res.json({ message }),
        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 updateMyProjects(req, res, next) {
    const {
      user,
      body: { projects: project }
    } = req;
    return user.updateMyProjects(project)
      .subscribe(
        message => res.json({ message }),
        next
      );
  }

  function updateMyUsername(req, res, next) {
    const { user, body: { username } } = req;
    return user.updateMyUsername(username)
    .subscribe(
      message => res.json({ message }),
      next
    );
  }

  api.post(
    '/refetch-user-challenge-map',
    ifNoUser401,
    refetchChallengeMap
  );
  api.post(
    '/update-flags',
    ifNoUser401,
    updateFlags
  );
  api.post(
    '/update-my-email',
    ifNoUser401,
    updateMyEmailValidators,
    createValidatorErrorHandler(alertTypes.danger),
    updateMyEmail
  );
  api.post(
    '/update-my-current-challenge',
    ifNoUser401,
    updateMyCurrentChallengeValidators,
    createValidatorErrorHandler(alertTypes.danger),
    updateMyCurrentChallenge
  );
  api.post(
    '/update-my-lang',
    ifNoUser401,
    updateMyLang
  );
  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.post(
    '/update-my-username',
    ifNoUser401,
    updateMyUsername
  );

  app.use(api);
}
