"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
    if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemoryService = void 0;
const common_1 = require("@nestjs/common");
const luxon_1 = require("luxon");
const decorators_1 = require("../decorators");
const memory_dto_1 = require("../dtos/memory.dto");
const enum_1 = require("../enum");
const base_service_1 = require("./base.service");
const asset_util_1 = require("../utils/asset.util");
const DAYS = 3;
let MemoryService = class MemoryService extends base_service_1.BaseService {
    async onMemoriesCreate() {
        const users = await this.userRepository.getList({ withDeleted: false });
        await this.databaseRepository.withLock(enum_1.DatabaseLock.MemoryCreation, async () => {
            const state = await this.systemMetadataRepository.get(enum_1.SystemMetadataKey.MemoriesState);
            const start = luxon_1.DateTime.utc().startOf('day').minus({ days: DAYS });
            const lastOnThisDayDate = state?.lastOnThisDayDate ? luxon_1.DateTime.fromISO(state.lastOnThisDayDate) : start;
            for (let i = 0; i <= DAYS * 2; i++) {
                const target = start.plus({ days: i });
                if (lastOnThisDayDate >= target) {
                    continue;
                }
                this.logger.log(`Creating memories for ${target.toISO()}`);
                try {
                    await Promise.all(users.map((owner) => this.createOnThisDayMemories(owner.id, target)));
                }
                catch (error) {
                    this.logger.error(`Failed to create memories for ${target.toISO()}: ${error}`);
                }
                await this.systemMetadataRepository.set(enum_1.SystemMetadataKey.MemoriesState, {
                    ...state,
                    lastOnThisDayDate: target.toISO(),
                });
            }
        });
    }
    async createOnThisDayMemories(ownerId, target) {
        const showAt = target.startOf('day').toISO();
        const hideAt = target.endOf('day').toISO();
        const memories = await this.assetRepository.getByDayOfYear([ownerId], target);
        await Promise.all(memories.map(({ year, assets }) => this.memoryRepository.create({
            ownerId,
            type: enum_1.MemoryType.OnThisDay,
            data: { year },
            memoryAt: target.set({ year }).toISO(),
            showAt,
            hideAt,
        }, new Set(assets.map(({ id }) => id)))));
    }
    async onMemoriesCleanup() {
        await this.memoryRepository.cleanup();
    }
    async search(auth, dto) {
        const memories = await this.memoryRepository.search(auth.user.id, dto);
        return memories
            .filter((memory) => memory.assets && memory.assets.length > 0)
            .map((memory) => (0, memory_dto_1.mapMemory)(memory, auth));
    }
    statistics(auth, dto) {
        return this.memoryRepository.statistics(auth.user.id, dto);
    }
    async get(auth, id) {
        await this.requireAccess({ auth, permission: enum_1.Permission.MemoryRead, ids: [id] });
        const memory = await this.findOrFail(id);
        return (0, memory_dto_1.mapMemory)(memory, auth);
    }
    async create(auth, dto) {
        const assetIds = dto.assetIds || [];
        const allowedAssetIds = await this.checkAccess({
            auth,
            permission: enum_1.Permission.AssetShare,
            ids: assetIds,
        });
        const memory = await this.memoryRepository.create({
            ownerId: auth.user.id,
            type: dto.type,
            data: dto.data,
            isSaved: dto.isSaved,
            memoryAt: dto.memoryAt,
            showAt: dto.showAt,
            hideAt: dto.hideAt,
            seenAt: dto.seenAt,
        }, allowedAssetIds);
        return (0, memory_dto_1.mapMemory)(memory, auth);
    }
    async update(auth, id, dto) {
        await this.requireAccess({ auth, permission: enum_1.Permission.MemoryUpdate, ids: [id] });
        const memory = await this.memoryRepository.update(id, {
            isSaved: dto.isSaved,
            memoryAt: dto.memoryAt,
            seenAt: dto.seenAt,
        });
        return (0, memory_dto_1.mapMemory)(memory, auth);
    }
    async remove(auth, id) {
        await this.requireAccess({ auth, permission: enum_1.Permission.MemoryDelete, ids: [id] });
        await this.memoryRepository.delete(id);
    }
    async addAssets(auth, id, dto) {
        await this.requireAccess({ auth, permission: enum_1.Permission.MemoryRead, ids: [id] });
        const repos = { access: this.accessRepository, bulk: this.memoryRepository };
        const results = await (0, asset_util_1.addAssets)(auth, repos, { parentId: id, assetIds: dto.ids });
        const hasSuccess = results.find(({ success }) => success);
        if (hasSuccess) {
            await this.memoryRepository.update(id, { updatedAt: new Date() });
        }
        return results;
    }
    async removeAssets(auth, id, dto) {
        await this.requireAccess({ auth, permission: enum_1.Permission.MemoryUpdate, ids: [id] });
        const repos = { access: this.accessRepository, bulk: this.memoryRepository };
        const results = await (0, asset_util_1.removeAssets)(auth, repos, {
            parentId: id,
            assetIds: dto.ids,
            canAlwaysRemove: enum_1.Permission.MemoryDelete,
        });
        const hasSuccess = results.find(({ success }) => success);
        if (hasSuccess) {
            await this.memoryRepository.update(id, { id, updatedAt: new Date() });
        }
        return results;
    }
    async findOrFail(id) {
        const memory = await this.memoryRepository.get(id);
        if (!memory) {
            throw new common_1.BadRequestException('Memory not found');
        }
        return memory;
    }
};
exports.MemoryService = MemoryService;
__decorate([
    (0, decorators_1.OnJob)({ name: enum_1.JobName.MemoryGenerate, queue: enum_1.QueueName.BackgroundTask }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], MemoryService.prototype, "onMemoriesCreate", null);
__decorate([
    (0, decorators_1.OnJob)({ name: enum_1.JobName.MemoryCleanup, queue: enum_1.QueueName.BackgroundTask }),
    __metadata("design:type", Function),
    __metadata("design:paramtypes", []),
    __metadata("design:returntype", Promise)
], MemoryService.prototype, "onMemoriesCleanup", null);
exports.MemoryService = MemoryService = __decorate([
    (0, common_1.Injectable)()
], MemoryService);
//# sourceMappingURL=memory.service.js.map