// TODO remove this setting after implemented all
/* eslint-disable no-unused-vars */
import { ErrorV3 } from '@growi/core';

import { SupportedAction } from '~/interfaces/activity';
import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
import loggerFactory from '~/utils/logger';

import { apiV3FormValidator } from '../../middlewares/apiv3-form-validator';


const logger = loggerFactory('growi:routes:apiv3:share-links');

const express = require('express');

const router = express.Router();

const { body, query, param } = require('express-validator');

const validator = {};

const today = new Date();

/**
 * @swagger
 *  tags:
 *    name: ShareLink
 */

module.exports = (crowi) => {
  const loginRequired = require('../../middlewares/login-required')(crowi);
  const adminRequired = require('../../middlewares/admin-required')(crowi);
  const addActivity = generateAddActivityMiddleware(crowi);

  const ShareLink = crowi.model('ShareLink');
  const Page = crowi.model('Page');

  const activityEvent = crowi.event('activity');

  /**
   * middleware to limit link sharing
   */
  const linkSharingRequired = (req, res, next) => {
    const isLinkSharingDisabled = crowi.configManager.getConfig('crowi', 'security:disableLinkSharing');
    logger.debug(`isLinkSharingDisabled: ${isLinkSharingDisabled}`);

    if (isLinkSharingDisabled) {
      return res.apiv3Err(new ErrorV3('Link sharing is disabled', 'link-sharing-disabled'));
    }
    next();
  };

  validator.getShareLinks = [
    // validate the page id is MongoId
    query('relatedPage').isMongoId().withMessage('Page Id is required'),
  ];

  /**
   * @swagger
   *
   *  paths:
   *    /share-links/:
   *      get:
   *        tags: [ShareLink]
   *        description: get share links
   *        parameters:
   *          - name: relatedPage
   *            in: query
   *            required: true
   *            description: page id of share link
   *            schema:
   *              type: string
   *        responses:
   *          200:
   *            description: Succeeded to get share links
   */
  router.get('/', loginRequired, linkSharingRequired, validator.getShareLinks, apiV3FormValidator, async(req, res) => {
    const { relatedPage } = req.query;

    const page = await Page.findByIdAndViewer(relatedPage, req.user);

    if (page == null) {
      const msg = 'Page is not found or forbidden';
      logger.error('Error', msg);
      return res.apiv3Err(new ErrorV3(msg, 'get-shareLink-failed'));
    }

    try {
      const shareLinksResult = await ShareLink.find({ relatedPage }).populate({ path: 'relatedPage', select: 'path' });
      return res.apiv3({ shareLinksResult });
    }
    catch (err) {
      const msg = 'Error occurred in get share link';
      logger.error('Error', err);
      return res.apiv3Err(new ErrorV3(msg, 'get-shareLink-failed'));
    }
  });

  validator.shareLinkStatus = [
    // validate the page id is MongoId
    body('relatedPage').isMongoId().withMessage('Page Id is required'),
    // validate expireation date is not empty, is not before today and is date.
    body('expiredAt').if(value => value != null).isAfter(today.toString()).withMessage('Your Selected date is past'),
    // validate the length of description is max 100.
    body('description').isLength({ min: 0, max: 100 }).withMessage('Max length is 100'),
  ];

  /**
   * @swagger
   *
   *  paths:
   *    /share-links/:
   *      post:
   *        tags: [ShareLink]
   *        description: Create new share link
   *        parameters:
   *          - name: relatedPage
   *            in: query
   *            required: true
   *            description: page id of share link
   *            schema:
   *              type: string
   *          - name: expiredAt
   *            in: query
   *            description: expiration date of share link
   *            schema:
   *              type: string
   *          - name: description
   *            in: query
   *            description: description of share link
   *            schema:
   *              type: string
   *        responses:
   *          200:
   *            description: Succeeded to create one share link
   */

  router.post('/', loginRequired, linkSharingRequired, addActivity, validator.shareLinkStatus, apiV3FormValidator, async(req, res) => {
    const { relatedPage, expiredAt, description } = req.body;

    const page = await Page.findByIdAndViewer(relatedPage, req.user);

    if (page == null) {
      const msg = 'Page is not found or forbidden';
      logger.error('Error', msg);
      return res.apiv3Err(new ErrorV3(msg, 'post-shareLink-failed'));
    }

    const ShareLink = crowi.model('ShareLink');

    try {
      const postedShareLink = await ShareLink.create({ relatedPage, expiredAt, description });

      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_SHARE_LINK_CREATE });

      return res.apiv3(postedShareLink, 201);
    }
    catch (err) {
      const msg = 'Error occured in post share link';
      logger.error('Error', err);
      return res.apiv3Err(new ErrorV3(msg, 'post-shareLink-failed'));
    }
  });


  validator.deleteShareLinks = [
    // validate the page id is MongoId
    query('relatedPage').isMongoId().withMessage('Page Id is required'),
  ];

  /**
  * @swagger
  *
  *    /share-links/:
  *      delete:
  *        tags: [ShareLinks]
  *        summary: /share-links/
  *        description: delete all share links related one page
  *        parameters:
  *          - name: relatedPage
  *            in: query
  *            required: true
  *            description: page id of share link
  *            schema:
  *              type: string
  *        responses:
  *          200:
  *            description: Succeeded to delete o all share links related one page
  */
  router.delete('/', loginRequired, addActivity, validator.deleteShareLinks, apiV3FormValidator, async(req, res) => {
    const { relatedPage } = req.query;
    const page = await Page.findByIdAndViewer(relatedPage, req.user);

    if (page == null) {
      const msg = 'Page is not found or forbidden';
      logger.error('Error', msg);
      return res.apiv3Err(new ErrorV3(msg, 'delete-shareLinks-for-page-failed'));
    }

    try {
      const deletedShareLink = await ShareLink.remove({ relatedPage });

      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_SHARE_LINK_DELETE_BY_PAGE });

      return res.apiv3(deletedShareLink);
    }
    catch (err) {
      const msg = 'Error occured in delete share link';
      logger.error('Error', err);
      return res.apiv3Err(new ErrorV3(msg, 'delete-shareLink-failed'));
    }
  });

  /**
  * @swagger
  *
  *    /share-links/all:
  *      delete:
  *        tags: [ShareLinks]
  *        description: delete all share links
  *        responses:
  *          200:
  *            description: Succeeded to remove all share links
  */
  router.delete('/all', loginRequired, adminRequired, addActivity, async(req, res) => {

    try {
      const deletedShareLink = await ShareLink.deleteMany({});
      const { deletedCount } = deletedShareLink;

      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_SHARE_LINK_ALL_DELETE });

      return res.apiv3({ deletedCount });
    }
    catch (err) {
      const msg = 'Error occurred in delete all share link';
      logger.error('Error', err);
      return res.apiv3Err(new ErrorV3(msg, 'delete-all-shareLink-failed'));
    }
  });

  validator.deleteShareLink = [
    param('id').isMongoId().withMessage('ShareLink Id is required'),
  ];

  /**
  * @swagger
  *
  *    /share-links/{id}:
  *      delete:
  *        tags: [ShareLinks]
  *        description: delete one share link related one page
  *        parameters:
  *          - name: id
  *            in: path
  *            required: true
  *            description: id of share link
  *            schema:
  *              type: string
  *        responses:
  *          200:
  *            description: Succeeded to delete one share link
  */
  router.delete('/:id', loginRequired, addActivity, validator.deleteShareLink, apiV3FormValidator, async(req, res) => {
    const { id } = req.params;
    const { user } = req;

    try {
      const shareLinkToDelete = await ShareLink.findOne({ _id: id });

      // check permission
      if (!user.isAdmin) {
        const page = await Page.findByIdAndViewer(shareLinkToDelete.relatedPage, user);
        const isPageExists = (await Page.count({ _id: shareLinkToDelete.relatedPage }) > 0);
        if (page == null && isPageExists) {
          const msg = 'Page is not found or forbidden';
          logger.error('Error', msg);
          return res.apiv3Err(new ErrorV3(msg, 'delete-shareLink-failed'));
        }
      }

      // remove
      await shareLinkToDelete.remove();

      activityEvent.emit('update', res.locals.activity._id, { action: SupportedAction.ACTION_SHARE_LINK_DELETE });

      return res.apiv3({ deletedShareLink: shareLinkToDelete });
    }
    catch (err) {
      const msg = 'Error occurred in delete share link';
      logger.error('Error', err);
      return res.apiv3Err(new ErrorV3(msg, 'delete-shareLink-failed'));
    }

  });


  return router;
};
