const mongoose = require('mongoose');
// const crawlerModel = require('./models/crawlerModel');
// const executionModel = require('./models/executionModel');

// const categoryModel = require('./models/categoryModel');
// const productModel = require('./models/productModel');
const ObjectID = require('mongodb').ObjectID; // use mongoose instead

const websiteModel = require('../models/websiteModel');
const workerModel = require('../models/workerModel');
const productListModel = require('../models/productListModel');
const requestModel = require('../models/requestModel');

const _ = require('lodash');
const Promise = require('bluebird');
const URI = require('urijs');
// const URL = require('url'); // use urijs instead
// const noop = function () { }; // use promises instead

const Queue = require("../nsq");

const express = require('express');
const router = express.Router({
  mergeParams: true
});
/* params router level */
// productList_id
router.param('productList_id', function (req, res, next, name) {
  // should look like mongo DB ObjectId
  if (/^(?=[a-f\d]{24}$)(\d+[a-f]|[a-f]+\d)/i.test(name)) {
    next();
  } else {
    next('route');
  }
});
// request_id
router.param('request_id', function (req, res, next, name) {
  // should look like mongo DB ObjectId
  if (/^(?=[a-f\d]{24}$)(\d+[a-f]|[a-f]+\d)/i.test(name)) {
    next();
  } else {
    next('route');
  }
});

// TODO:
// 4. Get product lists by user





// post /productList/ -> create new empty productList
// (in:null, out: productList._id)
router.post('/', function (req, res, next) {

  return productListModel.saveNew({
    'name': req.body.name,
    'userId': req.userId,
    // 'createdAt' : 
    // 'updatedAt' : 
    // 'removedAt' : 
    'requests' : req.body.requests // ['59803f6581282f4c8532bbb7','59803f6581282f4c8532bbb8']

  }).then((list) => {
    return res.status(201).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});

// put /productList/5ad5a7dc1f8a2e63133766e7 -> update productList
// (in:null, out: productList._id)
router.put('/:productList_id', function (req, res, next) {
  return productListModel.updateById(
    req.params.productList_id,
    {
      'name': req.body.name,
      'userId': req.userId,
      // 'createdAt' : uses default
      // 'updatedAt': uses model statics
      // 'removedAt' : 
      // 'requests' : []
    }
  ).then((list) => {
    return res.status(200).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});

router.get('/:productList_id', function (req, res, next) {
  return productListModel.findById(
    req.params.productList_id,
    '-__v'
  ).then((list) => {
    return res.status(200).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});

router.get('/', function (req, res, next) {
  return productListModel.find(
    '-__v'
  ).then((list) => {
    return res.status(200).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});

// put /productList/5ad5a7dc1f8a2e63133766e7 -> update productList
// (in:null, out: productList._id)
router.put('/:productList_id/remove', function (req, res, next) {
  return productListModel.removeUserFromProductList(
    req.params.productList_id
  ).then((list) => {
    return res.status(200).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});

// put /productList/5ad5a7dc1f8a2e63133766e7/request -> add new request to productList
// (in:null, out: productList._id)
router.put('/:productList_id/request', function (req, res, next) {
  return productListModel.addRequestIdToProductListById(
    req.params.productList_id,
    req.body.requestId
  ).then((list) => {
    return res.status(201).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});


router.put('/:productList_id/request/:request_id/hide', function (req, res, next) {
  return productListModel.toggleRequestHiddenInProductList(
    true,
    req.params.productList_id,
    req.params.request_id
  ).then((list) => {
    return res.status(201).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});


router.put('/:productList_id/request/:request_id/show', function (req, res, next) {
  return productListModel.toggleRequestHiddenInProductList(
    false,
    req.params.productList_id,
    req.params.request_id
  ).then((list) => {
    return res.status(201).json(list);
  }).catch((err) => {
    return res.status(501).json(err);
  });
});












// get crawler by crawler_id
router.get('/:crawler_id', function (req, res, next) {
  const Crawl = new Crawler(req.params.crawler_id).get(req.params.crawler_id, function (err, crawler) {
    if (err) return next(err);
    if (!crawler) return res.status(410);
    return res.status(200).render('layout', {
      title: 'Crawler id = ' + crawler._id,
      message: JSON.stringify(crawler) + ' ' + crawler.startingLinks[0].value
    });
  });
});
// creates new crawler or updates the old one
// TODO: save function was re-written, test out if body have and heve no ID
router.post('/', function (req, res, next) {
  // TODO: req.body.crawlerCustomId == required
  const crawler = new Crawler(req.body).save(function (err) {
    if (err) return next(err);
    // console.log('c', crawler);
    return res.status(201).json(crawler._id);
  });
});

// starts crawler execution
router.post('/:crawler_id/start', function (req, res, next) {
  // Check if Crawler is valid
  new Crawler().get(req.params.crawler_id, function (err, crawlerObj) {
    if (err) return next(err);

    // If crawler is valid startPreProcessing
    return new Crawler().startPreProcessing(crawlerObj, function (err, executionDoc) {
      if (err) return next(err);

      return res.status(200).render('layout', {
        title: 'Crawler id = ',
        message: 'Crawler = ' + executionDoc._id + ' has started'
      });
    });
  });

  // TODO: Start Process Links with crawler data from MongoDB
  // TODO: if crawler_id does not match = res.404
  // TODO: if crawler starts = res:ok
  // TODO: if craweler fails to start res.error
});

module.exports = router;
