import express from 'express';
import passport from 'passport';
import { DB_NAME, getDatabaseClient } from '../db-utils';
import { MongoUser, User } from '../shared/models/user';
import { ObjectId } from 'bson';
import { Word } from '../shared/models/word';
import { MongoCategory } from '../shared/models/category';
import { MongoShelf } from '../shared/models/shelf';

export const userProfileRoutes = express.Router();

export const jwtAuthentication = passport.authenticate('jwt', { session: false });

userProfileRoutes.get('/profile/', jwtAuthentication, async (request, response) => {
    const user: MongoUser = (request.user as any);
    response.json({
        _id: user._id,
        name: user.name,
        email: user.email,
        isVerified: user.isVerified,
        categories: user.categories,
        favouriteWords: user.favouriteWords,
    });
    return;
});

// Get Deep copy of data
userProfileRoutes.get('/deep-copy/', jwtAuthentication, async (request, response) => {
    const user: MongoUser = (request.user as any);
    
    const categoryCollection = getDatabaseClient().db(DB_NAME).collection<MongoCategory>('categories');
    const shelfCollection = getDatabaseClient().db(DB_NAME).collection<MongoShelf>('shelves');
    const wordCollection = getDatabaseClient().db(DB_NAME).collection<Word>('words');

    const allDeepCategories: any = [];

    const allCategories = await categoryCollection.find({
        _id: { $in: user.categories.map(id => new ObjectId(id)) }
    }).toArray();

    if (allCategories === undefined) {
        response.status(200);
        response.json({
            _id: user._id,
            name: user.name,
            email: user.email,
            isVerified: user.isVerified,
            categories: []
        });
        return;
    }

    try {
        for (let i = 0; i < allCategories.length; i += 1) {
            if (allCategories[i].shelves) {
                const shelves: any = await shelfCollection.find({
                    _id: { $in: allCategories[i].shelves.map(id => new ObjectId(id)) }
                }).toArray();
    
                for (let j = 0; j < allCategories[i].shelves.length; j += 1) {
                    if (shelves[j].words) {
                        const words = await wordCollection.find({ 
                            _id: { $in: shelves[j].words.map((word: any) => new ObjectId(word.word)) }
                        }).toArray();
    
                        words.forEach((word, index) => {
                            shelves[j].words[index].word = word;
                        });
    
                    }
                }
    
                allDeepCategories.push({
                    ...allCategories[i],
                    shelves,
                });
            } else {
                allDeepCategories.push({
                    ...allCategories[i]
                })
            }
        }
    } catch {
        response.sendStatus(500);
        return;
    }

    response.status(200);
    response.json({
        _id: user._id,
        name: user.name,
        email: user.email,
        isVerified: user.isVerified,
        categories: allDeepCategories
    });

    return;
});

// Add favourite word

userProfileRoutes.post('/favourite-words/', jwtAuthentication, async (request, response) => {
    const user: MongoUser = (request.user as any);
    const userCollection = getDatabaseClient().db(DB_NAME).collection<MongoUser>('users');
    const wordCollection = getDatabaseClient().db(DB_NAME).collection<Word>('words');

    if (!user.favouriteWords) {
        user.favouriteWords = [];
    }

    if (!request.body.wordId) {
        response.status(400);
        response.send("Missing wordID");
        return;
    } else if (user.favouriteWords.includes(request.body.wordId)) {
        response.status(400);
        response.send("WordID already present");
        return;
    }

    const matchedWord = await wordCollection.findOne({
        _id: new ObjectId(request.body.wordId)
    });

    if (!matchedWord) {
        response.status(400);
        response.send("Word not present in the library");
        return;
    }

    user.favouriteWords.push(request.body.wordId);

    const updatedUser = await userCollection.updateOne({
        _id: new ObjectId(user._id)
    }, {
        $set: {
            favouriteWords: user.favouriteWords
        }
    });

    if (updatedUser.acknowledged) {
        response.sendStatus(200);
    } else {
        response.sendStatus(500);
    }

    return;
});

// Update favourite word
userProfileRoutes.put('/favourite-words/', jwtAuthentication, async (request, response) => {
    const user: MongoUser = (request.user as any);
    const userCollection = getDatabaseClient().db(DB_NAME).collection<MongoUser>('users');
    
    if (!request.body.favouriteWords) {
        response.status(400);
        response.send("Missing favouriteWords param");
        return;
    }

    const updatedUser = await userCollection.updateOne({
        _id: new ObjectId(user._id)
    }, {
        $set: {
            favouriteWords: request.body.favouriteWords
        }
    });

    if (updatedUser.acknowledged) {
        response.sendStatus(200);
    } else {
        response.sendStatus(500);
    }

    return;
});