import { Words } from 'types'
import { mongodb } from './mongodb'

const collection = mongodb.collection<Words>('words')

export const consumeOrganizationWords = async (organizationIdentity: string, quantity: number): Promise<void> => {
    const words = await collection
        .find({
            organizationIdentity,
            $expr: {
                $gt: ['$words', '$usedWords'],
            },
            $and: [{ $or: [{ expiration: undefined }, { expiration: { $gt: new Date() } }] }],
        })
        .sort({ expiration: 1 })
        .toArray()

    // Consume words while there are words to consume and quantity is not zero
    let i = 0
    while (i < words.length && quantity > 0) {
        const word = words[i]
        const remainingWords = word.words - word.usedWords
        const consumedWords = Math.min(remainingWords, quantity)
        await collection.updateOne({ _id: word._id }, { $inc: { usedWords: consumedWords } })
        quantity -= consumedWords
        i++
    }
}

export const getOrganizationWords = async (organizationIdentity: string): Promise<Words[]> => {
    return await collection
        .find({
            organizationIdentity,
            $expr: {
                $gt: ['$words', '$usedWords'],
            },
            $and: [{ $or: [{ expiration: undefined }, { expiration: { $gt: new Date() } }] }],
        })
        .sort({ expiration: 1 })
        .toArray()
}

export const getOrganizationBalance = async (organizationIdentity: string): Promise<number> => {
    const words = await getOrganizationWords(organizationIdentity)
    const totalWords = words.reduce((total, word) => total + word.words, 0)
    const usedWords = words.reduce((total, word) => total + word.usedWords, 0)

    return totalWords - usedWords
}

export const addOrganizationWords = async (
    words: Pick<Words, 'id' | 'organizationIdentity' | 'words' | 'expiration'>,
): Promise<void> => {
    await collection.insertOne({
        ...words,
        usedWords: 0,
        createdAt: new Date(),
    })
}
