"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChatRepository = void 0;
const typeorm_1 = require("typeorm");
const ormconfig_1 = require("../ormconfig");
const ChatAggregate_1 = require("../../Domain/Chat/ChatAggregate");
const ChatArchiveAggregate_1 = require("../../Domain/Chat/ChatArchiveAggregate");
const Logger_1 = require("../../Application/Services/Logger");
class ChatRepository {
    constructor() {
        this.repo = ormconfig_1.AppDataSource.getRepository(ChatAggregate_1.ChatAggregate);
        this.archiveRepo = ormconfig_1.AppDataSource.getRepository(ChatArchiveAggregate_1.ChatArchiveAggregate);
    }
    async create(chat) {
        const startTime = Date.now();
        try {
            const result = await this.repo.save(chat);
            (0, Logger_1.logDatabase)('Chat created successfully', undefined, Date.now() - startTime, {
                chatId: result.id,
                type: result.type,
                participants: result.users?.length || 0
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.create error', error);
            throw new Error('Failed to create chat in database');
        }
    }
    async findByPage(from, to) {
        const startTime = Date.now();
        try {
            const skip = from;
            const take = to - from + 1;
            const [chats, totalCount] = await this.repo.findAndCount({
                where: { state: (0, typeorm_1.Not)(ChatAggregate_1.ChatState.SOFT_DELETE) },
                order: { createDate: 'DESC' },
                skip,
                take
            });
            (0, Logger_1.logDatabase)('Chats page retrieved successfully', undefined, Date.now() - startTime, {
                from,
                to,
                returned: chats.length,
                totalCount
            });
            return { chats, totalCount };
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findByPage error', error);
            throw new Error('Failed to retrieve chats page from database');
        }
    }
    async findByPageIncludingDeleted(from, to) {
        const startTime = Date.now();
        try {
            const skip = from;
            const take = to - from + 1;
            const [chats, totalCount] = await this.repo.findAndCount({
                order: { createDate: 'DESC' },
                skip,
                take
            });
            (0, Logger_1.logDatabase)('Chats page retrieved successfully (including deleted)', undefined, Date.now() - startTime, {
                from,
                to,
                returned: chats.length,
                totalCount
            });
            return { chats, totalCount };
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findByPageIncludingDeleted error', error);
            throw new Error('Failed to retrieve chats page from database');
        }
    }
    async findById(id) {
        const startTime = Date.now();
        try {
            const result = await this.repo.findOne({
                where: {
                    id,
                    state: (0, typeorm_1.Not)(ChatAggregate_1.ChatState.SOFT_DELETE)
                }
            });
            (0, Logger_1.logDatabase)('Chat findById query completed', undefined, Date.now() - startTime, {
                found: !!result,
                chatId: id
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findById error', error);
            throw new Error('Failed to retrieve chat from database');
        }
    }
    async findByIdIncludingDeleted(id) {
        const startTime = Date.now();
        try {
            const result = await this.repo.findOneBy({ id });
            (0, Logger_1.logDatabase)('Chat findByIdIncludingDeleted query completed', undefined, Date.now() - startTime, {
                found: !!result,
                chatId: id
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findByIdIncludingDeleted error', error);
            throw new Error('Failed to retrieve chat from database');
        }
    }
    async findByUserId(userId) {
        const startTime = Date.now();
        try {
            const result = await this.repo
                .createQueryBuilder('chat')
                .where(':userId = ANY(chat.users)', { userId })
                .andWhere('chat.state != :softDelete', { softDelete: ChatAggregate_1.ChatState.SOFT_DELETE })
                .getMany();
            (0, Logger_1.logDatabase)('Chats retrieved by user id', `findByUserId(${userId})`, Date.now() - startTime, {
                userId,
                count: result.length
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findByUserId error', error);
            throw new Error('Failed to find chats by user id');
        }
    }
    async findByUserIdIncludingDeleted(userId) {
        const startTime = Date.now();
        try {
            const result = await this.repo
                .createQueryBuilder('chat')
                .where(':userId = ANY(chat.users)', { userId })
                .getMany();
            (0, Logger_1.logDatabase)('Chats retrieved by user id (including deleted)', `findByUserIdIncludingDeleted(${userId})`, Date.now() - startTime, {
                userId,
                count: result.length
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findByUserIdIncludingDeleted error', error);
            throw new Error('Failed to find all chats by user id');
        }
    }
    async findByGameId(gameId) {
        const startTime = Date.now();
        try {
            const result = await this.repo.findOneBy({
                gameId,
                type: ChatAggregate_1.ChatType.GAME,
                state: ChatAggregate_1.ChatState.ACTIVE
            });
            (0, Logger_1.logDatabase)('Chat retrieved by game id', `findByGameId(${gameId})`, Date.now() - startTime, {
                gameId,
                found: !!result
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findByGameId error', error);
            throw new Error('Failed to find chat by game id');
        }
    }
    async findActiveChatsForUser(userId) {
        const startTime = Date.now();
        try {
            const result = await this.repo
                .createQueryBuilder('chat')
                .where(':userId = ANY(chat.users)', { userId })
                .andWhere('chat.state = :state', { state: ChatAggregate_1.ChatState.ACTIVE })
                .orderBy('chat.lastActivity', 'DESC')
                .getMany();
            (0, Logger_1.logDatabase)('Active chats retrieved for user', `findActiveChatsForUser(${userId})`, Date.now() - startTime, {
                userId,
                count: result.length
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findActiveChatsForUser error', error);
            throw new Error('Failed to find active chats for user');
        }
    }
    async findInactiveChats(inactivityMinutes) {
        const startTime = Date.now();
        try {
            const cutoffDate = new Date(Date.now() - inactivityMinutes * 60 * 1000);
            const result = await this.repo
                .createQueryBuilder('chat')
                .where('chat.state = :state', { state: ChatAggregate_1.ChatState.ACTIVE })
                .andWhere('(chat.lastActivity < :cutoffDate OR chat.lastActivity IS NULL)', { cutoffDate })
                .getMany();
            (0, Logger_1.logDatabase)('Inactive chats retrieved', `findInactiveChats(${inactivityMinutes}min)`, Date.now() - startTime, {
                inactivityMinutes,
                count: result.length,
                cutoffDate
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.findInactiveChats error', error);
            throw new Error('Failed to find inactive chats');
        }
    }
    async update(id, update) {
        const startTime = Date.now();
        try {
            await this.repo.update(id, update);
            const result = await this.findById(id);
            (0, Logger_1.logDatabase)('Chat updated successfully', `update(${id})`, Date.now() - startTime, {
                chatId: id,
                updatedFields: Object.keys(update),
                success: !!result
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.update error', error);
            throw new Error('Failed to update chat in database');
        }
    }
    async delete(id) {
        const startTime = Date.now();
        try {
            const result = await this.repo.delete(id);
            (0, Logger_1.logDatabase)('Chat deleted', `delete(${id})`, Date.now() - startTime, {
                chatId: id,
                affected: result.affected
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.delete error', error);
            throw new Error('Failed to delete chat');
        }
    }
    async softDelete(id) {
        const startTime = Date.now();
        try {
            await this.repo.update(id, { state: ChatAggregate_1.ChatState.SOFT_DELETE });
            const result = await this.findById(id);
            (0, Logger_1.logDatabase)('Chat soft deleted', `softDelete(${id})`, Date.now() - startTime, {
                chatId: id,
                success: !!result
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.softDelete error', error);
            throw new Error('Failed to soft delete chat');
        }
    }
    async archiveChat(chat) {
        const startTime = Date.now();
        try {
            const archive = new ChatArchiveAggregate_1.ChatArchiveAggregate();
            archive.chatId = chat.id;
            archive.archivedMessages = chat.messages;
            archive.archivedAt = new Date();
            archive.chatType = chat.type;
            archive.chatName = chat.name;
            archive.gameId = chat.gameId;
            archive.participants = chat.users;
            const archivedResult = await this.archiveRepo.save(archive);
            await this.repo.update(chat.id, {
                state: ChatAggregate_1.ChatState.ARCHIVE,
                messages: [],
                archiveDate: new Date()
            });
            (0, Logger_1.logDatabase)('Chat archived successfully', `archiveChat(${chat.id})`, Date.now() - startTime, {
                chatId: chat.id,
                messageCount: chat.messages.length,
                archiveId: archivedResult.id
            });
            return archivedResult;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.archiveChat error', error);
            throw new Error('Failed to archive chat');
        }
    }
    async getArchivedChat(chatId) {
        const startTime = Date.now();
        try {
            const result = await this.archiveRepo.findOneBy({ chatId });
            (0, Logger_1.logDatabase)('Archived chat retrieved', `getArchivedChat(${chatId})`, Date.now() - startTime, {
                chatId,
                found: !!result
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.getArchivedChat error', error);
            throw new Error('Failed to retrieve archived chat');
        }
    }
    async restoreFromArchive(chatId) {
        const startTime = Date.now();
        try {
            const archive = await this.archiveRepo.findOneBy({ chatId });
            if (!archive) {
                return null;
            }
            // Game chats cannot be restored, only viewed
            if (archive.chatType === ChatAggregate_1.ChatType.GAME) {
                (0, Logger_1.logDatabase)('Game chat restore attempt blocked', `restoreFromArchive(${chatId})`, Date.now() - startTime, {
                    chatId,
                    chatType: archive.chatType,
                    blocked: true
                });
                return null;
            }
            // Restore messages to the chat
            await this.repo.update(chatId, {
                state: ChatAggregate_1.ChatState.ACTIVE,
                messages: archive.archivedMessages,
                lastActivity: new Date(),
                archiveDate: null
            });
            const result = await this.findById(chatId);
            (0, Logger_1.logDatabase)('Chat restored from archive', `restoreFromArchive(${chatId})`, Date.now() - startTime, {
                chatId,
                messageCount: archive.archivedMessages.length,
                success: !!result
            });
            return result;
        }
        catch (error) {
            (0, Logger_1.logError)('ChatRepository.restoreFromArchive error', error);
            throw new Error('Failed to restore chat from archive');
        }
    }
}
exports.ChatRepository = ChatRepository;
//# sourceMappingURL=ChatRepository.js.map