"use strict";
/*
 * server component for the TimeLimit App
 * Copyright (C) 2019 - 2022 Jonas Lochmann
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRoundedTimestamp = void 0;
exports.dispatchAddUsedTime = dispatchAddUsedTime;
const minuteofday_1 = require("../../../../util/minuteofday");
const illegal_state_1 = require("../exception/illegal-state");
const missing_item_1 = require("../exception/missing-item");
const getRoundedTimestamp = () => {
    const now = Date.now();
    return now - (now % (1000 * 60 * 60 * 24 * 2 /* 2 days */));
};
exports.getRoundedTimestamp = getRoundedTimestamp;
const dayLengthInMinutes = minuteofday_1.MinuteOfDay.LENGTH;
const dayLengthInMs = dayLengthInMinutes * 1000 * 60;
async function dispatchAddUsedTime({ action, cache }) {
    const roundedTimestamp = (0, exports.getRoundedTimestamp)().toString(10);
    const categoryEntryUnsafe = await cache.database.category.findOne({
        where: {
            familyId: cache.familyId,
            categoryId: action.categoryId
        },
        transaction: cache.transaction,
        attributes: [
            'childId',
            'parentCategoryId',
            'extraTimeInMillis'
        ]
    });
    // verify that the category exists
    if (!categoryEntryUnsafe) {
        throw new missing_item_1.MissingCategoryException();
    }
    const categoryEntry = {
        childId: categoryEntryUnsafe.childId,
        parentCategoryId: categoryEntryUnsafe.parentCategoryId,
        extraTimeInMillis: categoryEntryUnsafe.extraTimeInMillis
    };
    const handleAddUsedTime = async ({ categoryId, currentExtraTime }) => {
        if (action.timeToAdd !== 0) {
            const oldItem = await cache.database.usedTime.findOne({
                where: {
                    familyId: cache.familyId,
                    categoryId: action.categoryId,
                    dayOfEpoch: action.dayOfEpoch,
                    startMinuteOfDay: minuteofday_1.MinuteOfDay.MIN,
                    endMinuteOfDay: minuteofday_1.MinuteOfDay.MAX
                },
                transaction: cache.transaction
            });
            if (oldItem) {
                const oldUsedTime = oldItem.usedTime;
                const newUsedTime = Math.max(0, Math.min(oldUsedTime + action.timeToAdd, dayLengthInMs));
                const oldLastUpdate = parseInt(oldItem.lastUpdate, 10);
                const newLastUpdate = parseInt(roundedTimestamp, 10);
                if (oldUsedTime !== newUsedTime || oldLastUpdate !== newLastUpdate) {
                    const [updatedRows] = await cache.database.usedTime.update({
                        usedTime: newUsedTime,
                        lastUpdate: newLastUpdate.toString(10)
                    }, {
                        where: {
                            familyId: cache.familyId,
                            categoryId: action.categoryId,
                            dayOfEpoch: action.dayOfEpoch,
                            startMinuteOfDay: minuteofday_1.MinuteOfDay.MIN,
                            endMinuteOfDay: minuteofday_1.MinuteOfDay.MAX
                        },
                        transaction: cache.transaction
                    });
                    if (updatedRows === 0) {
                        throw new illegal_state_1.IllegalStateException({ staticMessage: 'could not update fetched row' });
                    }
                }
            }
            else {
                await cache.database.usedTime.create({
                    familyId: cache.familyId,
                    categoryId: action.categoryId,
                    dayOfEpoch: action.dayOfEpoch,
                    usedTime: Math.max(0, Math.min(action.timeToAdd, dayLengthInMs)),
                    lastUpdate: roundedTimestamp,
                    startMinuteOfDay: minuteofday_1.MinuteOfDay.MIN,
                    endMinuteOfDay: minuteofday_1.MinuteOfDay.MAX
                }, {
                    transaction: cache.transaction
                });
            }
        }
        if (action.extraTimeToSubtract !== 0) {
            await cache.database.category.update({
                extraTimeInMillis: Math.max(0, currentExtraTime - action.extraTimeToSubtract)
            }, {
                where: {
                    familyId: cache.familyId,
                    categoryId: categoryId
                },
                transaction: cache.transaction
            });
            cache.categoriesWithModifiedBaseData.add(categoryId);
        }
        cache.categoriesWithModifiedUsedTimes.add(categoryId);
    };
    await handleAddUsedTime({
        categoryId: action.categoryId,
        currentExtraTime: categoryEntry.extraTimeInMillis
    });
    if (categoryEntry.parentCategoryId !== '') {
        const parentCategoryEntry = await cache.database.category.findOne({
            where: {
                familyId: cache.familyId,
                categoryId: categoryEntry.parentCategoryId,
                childId: categoryEntry.childId
            },
            transaction: cache.transaction
        });
        if (parentCategoryEntry) {
            await handleAddUsedTime({
                categoryId: categoryEntry.parentCategoryId,
                currentExtraTime: parentCategoryEntry.extraTimeInMillis
            });
        }
    }
    cache.incrementTriggeredSyncLevel(1);
}
//# sourceMappingURL=addusedtime.js.map