// This router code is responsible for handling the queries related to users

//Required modules
const express = require('express');
const path = require('path');
const fs = require("fs");
const faker = require('faker'); //For generating random data

// This router is mounted at "/reviews" ... you can see in store-server.js
let router = express.Router();

// These routes are relative to where the router is mounted. They are executed in 
// order since the first two call next() before they return
// These three handle GET requests to /users, one after the other.
router.get("/", queryParser);    // Parse the query parameters
router.get("/", loadReviews);    // Load matching reviews
router.get("/", respondReviews); // Send the response

// Handles POST requests to /reviews by making use of the JSON body parser
router.post("/", express.json(), createReview); // Parse the body, then create a random review

// These handle GET and PUT requests for a specific review's details.
router.get("/:id", getReview, sendSingleReview);
router.put("/:id", express.json(), saveReview);


// Parse the query parameters:
//    limit:    integer specifying maximum number of results to send back
//    page:     integer specifying page of results to send back (start is (page-1)*limit)
function queryParser(req, res, next) {
	const MAX_REVIEWS = 50;

    // If the limit parameter is missing, use a default of 10
	if (!req.query.limit) 
		req.query.limit = 10;
	
    // If the limit is larger than we allow, use the max
	if (req.query.limit > MAX_REVIEWS) 
		req.query.limit = MAX_REVIEWS;

    // If the page parameter is missing, use a default of 1
	if (!req.query.page) 
		req.query.page = 1;
	
    // If the page is less than 1, use the min
	if (req.query.page < 1) 
		req.query.page = 1;
	
    // Try to convert the page parameter to a number
	try {
		req.query.page = Number(req.query.page);
	} catch {
        // Set a default value (or undefined/ignore) if parsing fails
		req.query.page = 1;
	}

	next();  // Make sure to do this to handle the next middelware
}



// Load a review and add it to the request object
function getReview(req, res, next) {
    // Get the file for the product whose ID is in the request parameters
	let fileName = path.join(".", req.app.locals.config.reviewDir, req.params.id + ".json");

	// If the file exists, load the reviews's details, parse it and 
    // set the review property to the loaded detail data before calling the next middleware
	if (fs.existsSync(fileName)) {
		let data = fs.readFileSync(fileName);
		req.review = JSON.parse(data);
		next();
	} else {
		res.status(404).send("Could not find review with ID: " + req.params.id);
	}
}


// Save changes to a review that are given in the request body (i.e., from a PUT).
function saveReview(req, res, next) {
    // Get the file for the review whose ID is in the request parameters
	let fileName = path.join(".", req.app.locals.config.reviewDir, req.params.id + ".json");

    // Only update the review if there is already a review with the specified ID
	if (fs.existsSync(fileName)) {
		fs.writeFileSync(fileName, JSON.stringify(req.body));
		res.status(200).send("Review saved.");
	} else {
		res.status(404).send("Could not find review with ID: " + req.params.id);
	}
}


// Load the correct set of reviews based on the query parameters.
// This code adds a reviews property to the response object which is used later to send the response.
// The code works similar to the user router, but has different checks for product matching.
function loadReviews(req, res, next) {
	let results = [];
	let startIndex = (req.query.page-1) * Number(req.query.limit);

	fs.readdir(path.join(".", req.app.locals.config.reviewDir), function(err, items) {
		let count = 0;
		for (let fileNum=0; fileNum < items.length; fileNum++) {
			let data = fs.readFileSync(path.join(".", req.app.locals.config.reviewDir, items[fileNum]));
			let review = JSON.parse(data);
			// Add it to the results if at least at the correct index for the page
            if (count >= startIndex) 
				results.push(review);
			// If we have reached the limit for results, then stop reading
            if (results.length >= req.query.limit) 
				break;
			count++;  // Increase the count ... we need this for pagination
		}
		//Update the response object
		res.reviews = results;
		next();
	});
}


// Send a response (as either the reviews page or a JSON object of reviews)
function respondReviews(req, res, next) {
    res.format({
        "text/html": () => {
            res.render('pages/reviews', {
                reviews: res.reviews,
                page: req.query.page,
                config: req.app.locals.config
            });
        },
        "application/json": () => {
            res.json(res.reviews);
        }
    });
}



// Create a new review with fake details. In a real system, this would likely be entered
// by a user via a wen form.
function createReview(req, res, next) {
	let r = {}; // Create the review

	r.id = req.app.locals.config.nextReviewID;
	r.reviewer = req.body.reviewer;
	r.product = req.body.product;
	r.rating = Math.floor(Math.random()*5) + 1;
	r.summary = faker.lorem.sentence(); // This will look like latin and will make no sense
	r.review = faker.lorem.paragraph(); // This will look like latin and will make no sense

    // Update the config file and save the review info to a new file
	req.app.locals.config.nextReviewID++;
	fs.writeFileSync("config.json", JSON.stringify(req.app.locals.config));
	fs.writeFileSync(path.join(".", req.app.locals.config.reviewDir, r.id + ".json"), JSON.stringify(r));
	res.status(201).send(r);
}


// Send a single review that is specified as a property in the request object.
// It will send either JSON or an HTML page, depending on the Accepts header
function sendSingleReview(req, res, next){
    res.format({
        "text/html": () => {
            res.render('pages/review-profile', {
            review: req.review,
            config: req.app.locals.config
        });
        },
        "application/json": () => {
            res.json(req.review);
        }
    });
	next();
}

// Export the router object so we can access it in the base app
module.exports = router;
