"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DeckRepository = void 0;
const typeorm_1 = require("typeorm");
const ormconfig_1 = require("../ormconfig");
const DeckAggregate_1 = require("../../Domain/Deck/DeckAggregate");
const Logger_1 = require("../../Application/Services/Logger");
const AdminBypassService_1 = require("../../Application/Services/AdminBypassService");
class DeckRepository {
    constructor() {
        this.repo = ormconfig_1.AppDataSource.getRepository(DeckAggregate_1.DeckAggregate);
    }
    async create(deck) {
        return this.repo.save(deck);
    }
    async findByPage(from, to) {
        const startTime = performance.now();
        try {
            const limit = to - from + 1;
            const offset = from;
            // Get total count for pagination
            const totalCount = await this.repo.count({
                where: { state: (0, typeorm_1.Not)(DeckAggregate_1.State.SOFT_DELETE) }
            });
            // Get paginated results
            const decks = await this.repo.find({
                where: { state: (0, typeorm_1.Not)(DeckAggregate_1.State.SOFT_DELETE) },
                order: { updatedate: 'DESC' },
                take: limit,
                skip: offset
            });
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck page query completed', `executionTime: ${Math.round(endTime - startTime)}ms, found: ${decks.length}, total: ${totalCount}, from: ${from}, to: ${to}`);
            return { decks, totalCount };
        }
        catch (error) {
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck page query failed', `executionTime: ${Math.round(endTime - startTime)}ms, from: ${from}, to: ${to}`);
            (0, Logger_1.logError)('DeckRepository.findByPage error', error instanceof Error ? error : new Error(String(error)));
            throw new Error('Failed to get decks page from database');
        }
    }
    async findByPageIncludingDeleted(from, to) {
        const startTime = performance.now();
        try {
            const limit = to - from + 1;
            const offset = from;
            // Get total count for pagination
            const totalCount = await this.repo.count();
            // Get paginated results
            const decks = await this.repo.find({
                order: { updatedate: 'DESC' },
                take: limit,
                skip: offset
            });
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck page query completed (including deleted)', `executionTime: ${Math.round(endTime - startTime)}ms, found: ${decks.length}, total: ${totalCount}, from: ${from}, to: ${to}`);
            return { decks, totalCount };
        }
        catch (error) {
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck page query failed (including deleted)', `executionTime: ${Math.round(endTime - startTime)}ms, from: ${from}, to: ${to}`);
            (0, Logger_1.logError)('DeckRepository.findByPageIncludingDeleted error', error instanceof Error ? error : new Error(String(error)));
            throw new Error('Failed to get decks page from database');
        }
    }
    async findById(id) {
        return this.repo.findOne({
            where: {
                id,
                state: (0, typeorm_1.Not)(DeckAggregate_1.State.SOFT_DELETE)
            }
        });
    }
    async findByIdIncludingDeleted(id) {
        return this.repo.findOneBy({ id });
    }
    async update(id, update) {
        await this.repo.update(id, update);
        return this.findById(id);
    }
    async delete(id) {
        return this.repo.delete(id);
    }
    async softDelete(id) {
        await this.repo.update(id, { state: DeckAggregate_1.State.SOFT_DELETE });
        return this.findById(id);
    }
    async search(query, limit = 20, offset = 0) {
        const startTime = performance.now();
        try {
            const searchPattern = `%${query.toLowerCase()}%`;
            const queryBuilder = this.repo.createQueryBuilder('deck')
                .where('deck.state != :softDelete', { softDelete: DeckAggregate_1.State.SOFT_DELETE })
                .andWhere('LOWER(deck.name) LIKE :pattern', { pattern: searchPattern });
            const totalCount = await queryBuilder.getCount();
            const decks = await queryBuilder
                .orderBy('deck.name', 'ASC')
                .limit(limit)
                .offset(offset)
                .getMany();
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck search completed', `executionTime: ${Math.round(endTime - startTime)}ms, found: ${decks.length}, total: ${totalCount}, searchTerm: "${query}", limit: ${limit}, offset: ${offset}`);
            return { decks, totalCount };
        }
        catch (error) {
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck search failed', `executionTime: ${Math.round(endTime - startTime)}ms, searchTerm: "${query}"`);
            (0, Logger_1.logError)('DeckRepository.search error', error instanceof Error ? error : new Error(String(error)));
            throw new Error('Failed to search decks in database');
        }
    }
    async searchIncludingDeleted(query, limit = 20, offset = 0) {
        const startTime = performance.now();
        try {
            const searchPattern = `%${query.toLowerCase()}%`;
            const queryBuilder = this.repo.createQueryBuilder('deck')
                .where('LOWER(deck.name) LIKE :pattern', { pattern: searchPattern });
            const totalCount = await queryBuilder.getCount();
            const decks = await queryBuilder
                .orderBy('deck.name', 'ASC')
                .limit(limit)
                .offset(offset)
                .getMany();
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck search completed (including deleted)', `executionTime: ${Math.round(endTime - startTime)}ms, found: ${decks.length}, total: ${totalCount}, searchTerm: "${query}", limit: ${limit}, offset: ${offset}`);
            return { decks, totalCount };
        }
        catch (error) {
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Deck search failed (including deleted)', `executionTime: ${Math.round(endTime - startTime)}ms, searchTerm: "${query}"`);
            (0, Logger_1.logError)('DeckRepository.searchIncludingDeleted error', error instanceof Error ? error : new Error(String(error)));
            throw new Error('Failed to search all decks in database');
        }
    }
    /**
     * Count active (non-soft-deleted) decks for a specific user
     * @param userId - User ID to count decks for
     * @returns Number of active decks
     */
    async countActiveByUserId(userId) {
        const startTime = performance.now();
        try {
            const count = await this.repo.count({
                where: {
                    userid: userId,
                    state: (0, typeorm_1.Not)(DeckAggregate_1.State.SOFT_DELETE)
                }
            });
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('User active deck count completed', `executionTime: ${Math.round(endTime - startTime)}ms, userId: ${userId}, count: ${count}`);
            return count;
        }
        catch (error) {
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('User active deck count failed', `executionTime: ${Math.round(endTime - startTime)}ms, userId: ${userId}`);
            (0, Logger_1.logError)('DeckRepository.countActiveByUserId error', error instanceof Error ? error : new Error(String(error)));
            throw new Error('Failed to count active decks for user');
        }
    }
    /**
     * Count organizational decks for a specific user
     * @param userId - User ID to count organizational decks for
     * @returns Number of organizational decks
     */
    async countOrganizationalByUserId(userId) {
        const startTime = performance.now();
        try {
            const count = await this.repo.count({
                where: {
                    userid: userId,
                    ctype: DeckAggregate_1.CType.ORGANIZATION,
                    state: (0, typeorm_1.Not)(DeckAggregate_1.State.SOFT_DELETE)
                }
            });
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('User organizational deck count completed', `executionTime: ${Math.round(endTime - startTime)}ms, userId: ${userId}, count: ${count}`);
            return count;
        }
        catch (error) {
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('User organizational deck count failed', `executionTime: ${Math.round(endTime - startTime)}ms, userId: ${userId}`);
            (0, Logger_1.logError)('DeckRepository.countOrganizationalByUserId error', error instanceof Error ? error : new Error(String(error)));
            throw new Error('Failed to count organizational decks for user');
        }
    }
    /**
     * Find decks with filtering based on user permissions and mandatory pagination
     * @param userId - User ID for filtering
     * @param userOrgId - User's organization ID (if any)
     * @param isAdmin - Whether user is admin (bypasses filtering)
     * @param from - Start index for pagination (default: 0)
     * @param to - End index for pagination (default: 49)
     * @returns Paginated filtered list of decks with total count
     */
    async findFilteredDecks(userId, userOrgId, isAdmin, from = 0, to = 49) {
        const startTime = performance.now();
        try {
            // Validate pagination parameters
            if (from < 0 || to < from) {
                throw new Error('Invalid pagination parameters');
            }
            const limit = to - from + 1;
            if (limit > 100) {
                throw new Error('Page size too large. Maximum 100 records per request');
            }
            const skip = from;
            const take = limit;
            // Admin gets ALL decks with pagination
            if (isAdmin) {
                AdminBypassService_1.AdminBypassService.logAdminBypass('FIND_FILTERED_DECKS_BYPASS', userId, 'all-decks-filtered', {
                    bypassType: 'admin-all-decks-filtered',
                    userOrgId,
                    from,
                    to,
                    operation: 'read'
                });
                const [decks, totalCount] = await this.repo.findAndCount({
                    where: { state: (0, typeorm_1.Not)(DeckAggregate_1.State.SOFT_DELETE) },
                    relations: ['organization'],
                    order: { creationdate: 'DESC' },
                    skip,
                    take
                });
                const endTime = performance.now();
                (0, Logger_1.logDatabase)('Admin filtered deck query completed', `executionTime: ${Math.round(endTime - startTime)}ms, userId: ${userId}, found: ${decks.length}, totalCount: ${totalCount}, isAdmin: true`);
                return { decks, totalCount };
            }
            // Regular user complex filtering
            const queryBuilder = this.repo.createQueryBuilder('deck')
                .leftJoinAndSelect('deck.organization', 'org')
                .where('deck.state != :deletedState', { deletedState: DeckAggregate_1.State.SOFT_DELETE });
            queryBuilder.andWhere('(' +
                // User's private decks
                '(deck.userid = :userId AND deck.ctype = :privateType) OR ' +
                // All public decks
                '(deck.ctype = :publicType)' +
                // Organization decks from same org (if user has org)
                (userOrgId ? ' OR (deck.ctype = :orgType AND org.id = :orgId)' : '') +
                ')', {
                userId,
                privateType: DeckAggregate_1.CType.PRIVATE,
                publicType: DeckAggregate_1.CType.PUBLIC,
                ...(userOrgId && { orgType: DeckAggregate_1.CType.ORGANIZATION, orgId: userOrgId })
            });
            queryBuilder
                .orderBy('deck.creationdate', 'DESC')
                .skip(skip)
                .take(take);
            const [decks, totalCount] = await queryBuilder.getManyAndCount();
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('User filtered deck query completed', `executionTime: ${Math.round(endTime - startTime)}ms, userId: ${userId}, userOrgId: ${userOrgId}, found: ${decks.length}, totalCount: ${totalCount}, isAdmin: false`);
            return { decks, totalCount };
        }
        catch (error) {
            const endTime = performance.now();
            (0, Logger_1.logDatabase)('Filtered deck query failed', `executionTime: ${Math.round(endTime - startTime)}ms, userId: ${userId}, isAdmin: ${isAdmin}`);
            (0, Logger_1.logError)('DeckRepository.findFilteredDecks error', error instanceof Error ? error : new Error(String(error)));
            throw new Error('Failed to find filtered decks');
        }
    }
}
exports.DeckRepository = DeckRepository;
//# sourceMappingURL=DeckRepository.js.map