/** @module root/router */
'use strict';
// vim: set ts=2 sw=2 et tw=80:

const fs = require('fs');
const express = require('express');
const router = express.Router();

const mongoose = require('mongoose');
const Favorite = mongoose.model('Favorite');
const eventBus = require('../../pubsub');

const { error, catchErrs, renderFav, parseId, notFound } = require('../utils');

function socketEmit(req, name, fav) {
  const obj = {
    _id: fav._id,
    name: fav.name,
    dataURL: fav.dataURL,
    bookmarked: fav.bookmarked,
    socketid: req.query.socketid
  };

  eventBus.emit(name, obj);
}

async function findAndRender(filter, req, res) {
  try {
    if (filter.name) {
      filter.name = { $regex: filter.name, $options: 'i' };
    }
    const favs = await Favorite.find(filter);
    renderFav(req, res, favs);
  } catch(e) {
    error(e, res);
  }
}

router.post('/', async (req, res) => {
  if (!req.body.name || !req.body.dataURL) {
    res.writeHead(400, { 'Content-Type': 'text/plain' });
    res.end('Bad create form parameters');
    return;
  }

  const data = {
    name: req.body.name,
    dataURL: req.body.dataURL,
    bookmarked: req.body.bookmarked,
  };
  const favourite = new Favorite(data);

  if (req.body._id) {
    favourite._id = req.body._id;
  } else {
    favourite._id = mongoose.Types.ObjectId();
  }

  try {
    const fav = await favourite.save();
    res.status = 201;

    socketEmit(req, 'favorite.created', fav);

    renderFav(req, res, fav, false);
  } catch(e) {
    error(e, res);
  }
});

router.get('/', async (req, res) => {
  await findAndRender({}, req, res);
});

router.get('/search', async (req, res) => {
  const filter = Object.assign({}, req.query);
  delete filter['dataURL'];
  delete filter['_method'];
  delete filter['ajax'];

  await findAndRender(filter, req, res);
});

function findOne(id, created = false) {
  return async (req, res) => {
    try {
      const fav = await Favorite.findById(id(req));

      if (notFound(fav, res)) {
        return;
      }

      if (created) {
        socketEmit(req, 'favorite.created', fav);
      }

      renderFav(req, res, fav, false);
    } catch(e) {
      error(e, res);
    }
  };
}

router.get('/:id', findOne(req => parseId(req)));

function handleUpdate(partial = false) {
  return async (req, res) => {
    const edit = {};
    for (const key of ['dataURL', 'name']) {
      if (req.body[key]) {
        edit[key] = req.body[key];
      } else if (!partial) {
        res.writeHead(400, { 'Content-Type': 'text/plain' });
        res.end('Bad PUT form parameters');
        return;
      }
    }

    if (req.body.bookmarked !== undefined) {
      edit.bookmarked = req.body.bookmarked;
    }

    try {
      const fav = await Favorite.findByIdAndUpdate(parseId(req), { $set: edit }, {
        new: false,
        upsert: true,
        setDefaultsOnInsert: true,
      });

      if (fav == null) {
        res.status = 201;
        await findOne(() => parseId(req), true)(req, res);
        return;
      }

      res.status = 200;
      Object.assign(fav, edit);

      socketEmit(req, 'favorite.updated', fav);

      renderFav(req, res, fav, false);
    } catch (e) {
      error(e, res);
    }
  };
}

router.put('/:id', handleUpdate());

router.patch('/:id', handleUpdate(true));

router.delete('/:id', async (req, res) => {
  try {
    const fav = await Favorite.findByIdAndDelete(parseId(req));

    if (notFound(fav, res)) {
      return;
    }

    socketEmit(req, 'favorite.deleted', { _id: fav.id });

    res.format({
      json: () => res.writeHead(204),
      html: () => res.writeHead(302, { 'Location': '/favorites' })
    });
    res.end();
  } catch (e) {
    error(e, res);
  }
});

router.put('/:id/bookmarked', async (req, res) => {
  if (req.body.bookmarked !== true && req.body.bookmarked !== false &&
    req.body.bookmarked !== "true" && req.body.bookmarked !== "false") {
    res.writeHead(400, { 'Content-Type': 'text/plain' });
    res.end('Bad PUT bookmark form parameters');
  }

  try {
    const fav = await Favorite.findById(parseId(req));
    fav.bookmarked = req.body.bookmarked === true ||
      req.body.bookmarked === "true";
    fav.save();

    socketEmit(req, 'favorite.created', fav);

    renderFav(req, res, fav, false);
  } catch (e) {
    notFound(null, res);
  }
});

/** router for /root */
module.exports = router;
