const express = require('express');
const { wrapAsync, commonErrorHandler, isUuidV4 } = require('../helpers');
const { checkCrudPermissions } = require('../middlewares/check-permissions');
const { parse } = require('json2csv');

function createEntityRouter(entityName, Service, DBApi, options = {}) {
  const router = express.Router();

  const permissionEntity = options.permissionEntity || entityName;
  router.use(checkCrudPermissions(permissionEntity));

  router.post(
    '/',
    wrapAsync(async (req, res) => {
      const referer =
        req.headers.referer ||
        `${req.protocol}://${req.hostname}${req.originalUrl}`;
      const link = new URL(referer);
      const payload = await Service.create(
        req.body.data,
        req.currentUser,
        true,
        link.host,
      );
      res.status(200).send(payload);
    }),
  );

  router.post(
    '/bulk-import',
    wrapAsync(async (req, res) => {
      const referer =
        req.headers.referer ||
        `${req.protocol}://${req.hostname}${req.originalUrl}`;
      const link = new URL(referer);
      await Service.bulkImport(req, res, true, link.host);
      res.status(200).send(true);
    }),
  );

  router.put(
    '/:id',
    wrapAsync(async (req, res) => {
      await Service.update(req.body.data, req.body.id, req.currentUser);
      res.status(200).send(true);
    }),
  );

  router.delete(
    '/:id',
    wrapAsync(async (req, res) => {
      await Service.remove(req.params.id, req.currentUser);
      res.status(200).send(true);
    }),
  );

  router.post(
    '/deleteByIds',
    wrapAsync(async (req, res) => {
      await Service.deleteByIds(req.body.data, req.currentUser);
      res.status(200).send(true);
    }),
  );

  router.get(
    '/',
    wrapAsync(async (req, res) => {
      const filetype = req.query.filetype;
      const currentUser = req.currentUser;
      const runtimeContext = req.runtimeContext;

      const payload = await DBApi.findAll(req.query, {
        currentUser,
        runtimeContext,
      });

      if (filetype === 'csv') {
        const fields = options.csvFields ||
          DBApi.CSV_FIELDS || ['id', 'createdAt'];
        const opts = { fields };
        try {
          const csv = parse(payload.rows, opts);
          res.status(200).attachment('export.csv').send(csv);
        } catch (err) {
          console.error(err);
          res.status(500).send('CSV export error');
        }
      } else {
        res.status(200).send(payload);
      }
    }),
  );

  router.get(
    '/count',
    wrapAsync(async (req, res) => {
      const currentUser = req.currentUser;
      const runtimeContext = req.runtimeContext;
      const payload = await DBApi.findAll(req.query, {
        countOnly: true,
        currentUser,
        runtimeContext,
      });
      res.status(200).send(payload);
    }),
  );

  router.get(
    '/autocomplete',
    wrapAsync(async (req, res) => {
      const payload = await DBApi.findAllAutocomplete(
        req.query.query,
        req.query.limit,
        req.query.offset,
      );
      res.status(200).send(payload);
    }),
  );

  router.get(
    '/:id',
    wrapAsync(async (req, res) => {
      if (!isUuidV4(req.params.id)) {
        return res.status(400).send(`Invalid ${entityName} id`);
      }

      const runtimeContext = req.runtimeContext;
      const payload = await DBApi.findBy(
        { id: req.params.id },
        { runtimeContext },
      );
      res.status(200).send(payload);
    }),
  );

  if (options.customRoutes) {
    options.customRoutes(router, Service, DBApi);
  }

  router.use('/', commonErrorHandler);

  return router;
}

module.exports = { createEntityRouter, isUuidV4 };
