Source: src/routes/api/stats.js

"use strict";

const boom = require("@hapi/boom");

/**
 * Registers the stats API endpoints on the provided Hapi server instance.
 *
 * This function sets up the following routes:
 *
 * - **GET `/api.stats`**: Retrieves the stats for an authenticated user.
 * - **POST `/api/stats`**: Inserts a new stats record for an authenticated user.
 * - **PUT `/api/stats/{id}`**: Updates an existing stats record identified by an ID.
 * - **DELETE `/api/stats/{id}`**: Deletes a stats record identified by an ID.
 *
 * All routes use "try" authentication mode. If a request is made by an unauthenticated user, the endpoints
 * return an unauthorized response.
 *
 * @async
 * @function register
 * @param {Object} server - The Hapi server instance used to register routes.
 */
module.exports.register = async server => {
    server.route( {
        method: "GET",
        path: "/api.stats",
        options: {
            auth: {mode: "try"}
        },

    /**
     * GET /api.stats route handler.
     *
     * Retrieves the stats for an authenticated user. If the user is not authenticated,
     * an unauthorized error is returned.
     *
     * @async
     * @function
     * @param {Object} request - The Hapi request object.
     * @param {Object} request.auth - Authentication details.
     * @param {boolean} request.auth.isAuthenticated - Indicates if the user is authenticated.
     * @param {Object} request.auth.credentials - The credentials object.
     * @param {Object} request.auth.credentials.profile - The user profile details.
     * @param {(number|string)} request.auth.credentials.profile.id - The unique user ID.
     * @returns {Promise<Object[]|Object>} An array of stats records if successful or a Boom unauthorized error.
     */
        handler: async request => {
            try {
                if(!request.auth.isAuthenticated) {
                    return boom.unauthorized();
                }
                const db = request.server.plugins.sql.client;

                const userId = request.auth.credentials.profile.id;
                const res = await db.stats.getStats(userId);

                console.log("Stats fetched from database:", res.recordset); // Debug log
                return res.recordset;
            } catch (err) {
                console.log(err);
                return boom.boomify(err);
            }
        }
    });

    server.route({
        method: "POST",
        path: "/api/stats",
        options: {
            auth: {mode: "try"}
        },

    /**
     * POST /api/stats route handler.
     *
     * Inserts a new stats record for an authenticated user. The stats record includes various properties
     * such as gold amounts, pomodoro metrics, task counts, etc.
     *
     * @async
     * @function
     * @param {Object} request - The Hapi request object.
     * @param {Object} request.auth - Authentication details.
     * @param {boolean} request.auth.isAuthenticated - Indicates if the user is authenticated.
     * @param {Object} request.auth.credentials - The credentials object.
     * @param {Object} request.auth.credentials.profile - The user profile details.
     * @param {(number|string)} request.auth.credentials.profile.id - The unique user ID.
     * @param {Object} request.payload - The payload object containing stats data.
     * @param {number} request.payload.goldAmount - Current gold amount.
     * @param {number} request.payload.goldEarned - Total gold earned.
     * @param {number} request.payload.goldSpent - Total gold spent.
     * @param {number} request.payload.pomoCompleted - Number of pomodoros completed.
     * @param {number} request.payload.pomoTimeSpentMinutes - Time spent on pomodoros (in minutes).
     * @param {number} request.payload.tasksCompleted - Number of tasks completed.
     * @param {number} request.payload.habitsCompleted - Number of habits completed.
     * @param {number} request.payload.longestHabitStreak - Longest streak of habit completion.
     * @param {number} request.payload.stocksChecked - Count of stock checks.
     * @param {number} request.payload.weatherChecks - Count of weather checks.
     * @param {number} request.payload.movieLikes - Count of movie likes.
     * @param {number} request.payload.settingsChanged - Count of settings changes.
     * @param {number} request.payload.journalEntriesWritten - Count of journal entries written.
     * @param {number} request.payload.notesWritten - Count of notes written.
     * @returns {Promise<Object>} The newly inserted stats record or a Boom error if the operation fails.
     */
        handler: async request => {
            try {
                if (!request.auth.isAuthenticated) {
                    return boom.unauthorized();
                }
                const db = request.server.plugins.sql.client;
                const userId = request.auth.credentials.profile.id;
                const {goldAmount, goldEarned, goldSpent, pomoCompleted, pomoTimeSpentMinutes, tasksCompleted, habitsCompleted, longestHabitStreak, stocksChecked, weatherChecks, movieLikes, settingsChanged, journalEntriesWritten, notesWritten} = request.payload;
                const res = await db.stats.addStats({userId, goldAmount, goldEarned, goldSpent, pomoCompleted, pomoTimeSpentMinutes, tasksCompleted, habitsCompleted, longestHabitStreak, stocksChecked, weatherChecks, movieLikes, settingsChanged, journalEntriesWritten, notesWritten});
                return res.recordset[0];
            } catch (err) {
                console.log(err);
                return boom.boomify(err);
            }
        }
    });

    server.route({
        method: "PUT",
        path: "/api/stats/{id}",
        options: {
            auth: {mode: "try"}
        },

    /**
     * PUT /api/stats/{id} route handler.
     *
     * Updates an existing stats record for an authenticated user. This route expects the ID of the record to be updated
     * and the updated stats data in the payload.
     *
     * @async
     * @function
     * @param {Object} request - The Hapi request object.
     * @param {Object} request.auth - Authentication details.
     * @param {boolean} request.auth.isAuthenticated - Indicates if the user is authenticated.
     * @param {Object} request.auth.credentials - The credentials object.
     * @param {Object} request.auth.credentials.profile - The user profile details.
     * @param {(number|string)} request.auth.credentials.profile.id - The unique user ID.
     * @param {Object} request.params - URL parameters.
     * @param {(string|number)} request.params.id - The ID of the stats record to update.
     * @param {Object} request.payload - The payload object containing updated stats data.
     * @param {number} request.payload.goldAmount - Updated gold amount.
     * @param {number} request.payload.goldEarned - Updated total gold earned.
     * @param {number} request.payload.goldSpent - Updated total gold spent.
     * @param {number} request.payload.pomoCompleted - Updated number of pomodoros completed.
     * @param {number} request.payload.pomoTimeSpentMinutes - Updated pomodoro time (in minutes).
     * @param {number} request.payload.tasksCompleted - Updated number of tasks completed.
     * @param {number} request.payload.habitsCompleted - Updated number of habits completed.
     * @param {number} request.payload.longestHabitStreak - Updated longest habit streak.
     * @param {number} request.payload.stocksChecked - Updated count of stock checks.
     * @param {number} request.payload.weatherChecks - Updated count of weather checks.
     * @param {number} request.payload.movieLikes - Updated count of movie likes.
     * @param {number} request.payload.settingsChanged - Updated count of settings changes.
     * @param {number} request.payload.journalEntriesWritten - Updated count of journal entries written.
     * @param {number} request.payload.notesWritten - Updated count of notes written.
     * @returns {Promise<Object>} The updated stats record or a Boom error if the operation fails.
     */
        handler: async request => {
            try {
                if (!request.auth.isAuthenticated) {
                    return boom.unauthorized();
                }
                const db = request.server.plugins.sql.client;
                const userId = request.auth.credentials.profile.id;
                const {id} = request.params;
                const {goldAmount, goldEarned, goldSpent, pomoCompleted, pomoTimeSpentMinutes, tasksCompleted, habitsCompleted, longestHabitStreak, stocksChecked, weatherChecks, movieLikes, settingsChanged, journalEntriesWritten, notesWritten} = request.payload;

                const res = await db.stats.updateStats({id, userId, goldAmount, goldEarned, goldSpent, pomoCompleted, pomoTimeSpentMinutes, tasksCompleted, habitsCompleted, longestHabitStreak, stocksChecked, weatherChecks, movieLikes, settingsChanged, journalEntriesWritten, notesWritten});
                return res.recordset[0];
            } catch (err) {
                console.log(err);
                return boom.boomify(err);
            }
        }
    });

    server.route( {
        method: "DELETE",
        path: "/api/stats/{id}",
        options: {
            auth: {mode: "try"}
        },

    /**
     * DELETE /api/stats/{id} route handler.
     *
     * Deletes a stats record for an authenticated user. Returns a 204 No Content response if the deletion is successful.
     * If no record is found with the provided ID, a not-found error is returned.
     *
     * @async
     * @function
     * @param {Object} request - The Hapi request object.
     * @param {Object} request.auth - Authentication details.
     * @param {boolean} request.auth.isAuthenticated - Indicates if the user is authenticated.
     * @param {Object} request.auth.credentials - The credentials object.
     * @param {Object} request.auth.credentials.profile - The user profile details.
     * @param {(number|string)} request.auth.credentials.profile.id - The unique user ID.
     * @param {Object} request.params - URL parameters.
     * @param {(string|number)} request.params.id - The ID of the stats record to delete.
     * @param {Object} h - Hapi's response toolkit.
     * @returns {Promise<Object>} A 204 No Content response upon success, or a Boom error if the record is not found.
     */
        handler: async (request, h) => {
            try {
                if (!request.auth.isAuthenticated) {
                    return boom.unauthorized();
                }   
                const id = request.params.id;
                const userId = request.auth.credentials.profile.id;
                const db = request.server.plugins.sql.client;
                const res = await db.stats.deleteStats({id, userId});
                    
                return res.rowsAffected[0] === 1 ? h.response().code(204) : boom.notFound();
            } catch (err) {
                console.log(err);
                return boom.boomify(err);
            }
        }
    });

    server.route({
        method: "POST",
        path: "/api/stats/initialize",
        options: {
            auth: { mode: "try" }
        },
        handler: async request => {
            try {
                if (!request.auth.isAuthenticated) {
                    return boom.unauthorized();
                }

                const db = request.server.plugins.sql.client;
                const userId = request.auth.credentials.profile.id;

                // Initialize stats to 0
                const defaultStats = {
                    userId,
                    goldAmount: 0,
                    goldEarned: 0,
                    goldSpent: 0,
                    pomoCompleted: 0,
                    pomoTimeSpentMinutes: 0,
                    tasksCompleted: 0,
                    habitsCompleted: 0,
                    longestHabitStreak: 0,
                    stocksChecked: 0,
                    weatherChecks: 0,
                    movieLikes: 0,
                    settingsChanged: 0,
                    journalEntriesWritten: 0,
                    notesWritten: 0
                };

                console.log("Initializing stats with:", defaultStats); // Debug log

                // Insert default stats into the database
                const res = await db.stats.addStats(defaultStats);

                console.log("Stats initialized:", res.recordset); // Debug log
                return res.recordset[0];
            } catch (err) {
                console.log(err);
                return boom.boomify(err);
            }
        }
    });
};