"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getApplicationList = void 0;
const drizzle_orm_1 = require("drizzle-orm");
const database_1 = require("../../../database");
const tables_1 = require("../../../database/tables");
const logger_1 = __importDefault(require("../../../logger"));
const decimal_js_1 = __importDefault(require("decimal.js"));
const get_upgrade_meta_1 = require("../../../util/get-upgrade-meta");
const time_1 = require("../../../util/time");
const restriction_message_1 = require("../../constants/restriction.message");
/** Custom AI Application with upload (zip) setup — excludes shell/CLI-only apps. */
const isCustomAiUploadProviderSql = (0, drizzle_orm_1.sql) `(
  COALESCE(btrim(${tables_1.applicationsTable.provider_config}->'config'->>'custom_provider_type'), '') = 'Custom AI Application'
  AND (
    COALESCE(btrim(${tables_1.applicationsTable.provider_config}->'config'->'provider'->>'setupMethod'), '') = 'upload'
    OR (
      COALESCE(btrim(${tables_1.applicationsTable.provider_config}->'config'->'provider'->>'setupMethod'), '') = ''
      AND NULLIF(btrim(${tables_1.applicationsTable.provider_config}->'config'->'provider'->>'bundleBlobUrl'), '') IS NOT NULL
    )
  )
)`;
/** When excludeCustomProviders: allow non-custom apps, or Custom AI upload only. */
const excludeNonUploadCustomProvidersSql = (0, drizzle_orm_1.sql) `(
  COALESCE(btrim(${tables_1.applicationsTable.provider_config}->>'provider_type'), '') <> 'custom'
  OR (${isCustomAiUploadProviderSql})
)`;
const getApplicationList = async (req, res) => {
    try {
        const { projectId, page = 1, limit = 10, search, archived_data_required = 'true', orgId, getRestrictions = 'false', excludeCustomProviders = 'false', includeEvaluationEnabled = 'false', ensureApplicationId: ensureApplicationIdRaw, } = req.query;
        const ensureApplicationId = typeof ensureApplicationIdRaw === 'string' && ensureApplicationIdRaw.trim() !== ''
            ? ensureApplicationIdRaw.trim()
            : null;
        const parsedLimit = Number(limit);
        const parsedPage = Number(page);
        const offset = (parsedPage - 1) * parsedLimit;
        const includeArchived = archived_data_required === 'true';
        const shouldExcludeCustomProviders = excludeCustomProviders === 'true' || excludeCustomProviders === '1';
        const db = await (0, database_1.getDb)();
        /** JSONB `provider_config->>provider_type` is non-null and non-empty (evaluation-capable apps). */
        const providerConfigHasProviderType = (0, drizzle_orm_1.sql) `(
      ${tables_1.applicationsTable.provider_config}->>'provider_type' IS NOT NULL
      AND btrim(${tables_1.applicationsTable.provider_config}->>'provider_type') <> ''
    )`;
        const whereConditions = [];
        if (projectId) {
            whereConditions.push((0, drizzle_orm_1.eq)(tables_1.applicationsTable.projectId, projectId));
        }
        if (search && typeof search === 'string' && search.trim() !== '') {
            whereConditions.push((0, drizzle_orm_1.or)((0, drizzle_orm_1.ilike)(tables_1.applicationsTable.name, `%${search}%`), (0, drizzle_orm_1.ilike)(tables_1.applicationsTable.description, `%${search}%`)));
        }
        // Add archived filter if needed
        if (!includeArchived) {
            whereConditions.push((0, drizzle_orm_1.eq)(tables_1.applicationsTable.is_archived, false));
        }
        if (shouldExcludeCustomProviders) {
            whereConditions.push(excludeNonUploadCustomProvidersSql);
        }
        if (includeEvaluationEnabled === 'true') {
            whereConditions.push(providerConfigHasProviderType);
        }
        const applicationListSelect = {
            id: tables_1.applicationsTable.id,
            name: tables_1.applicationsTable.name,
            description: tables_1.applicationsTable.description,
            createdAt: tables_1.applicationsTable.createdAt,
            security_config: tables_1.applicationsTable.security_config,
            updatedAt: tables_1.applicationsTable.updatedAt,
            useCase: tables_1.applicationsTable.useCase,
            test_runs: tables_1.applicationsTable.test_runs,
            provider_config: tables_1.applicationsTable.provider_config,
            projectId: tables_1.applicationsTable.projectId,
            is_archived: tables_1.applicationsTable.is_archived,
            enableEncryption: tables_1.applicationsTable.enableEncryption,
            metrics: tables_1.pulseMonitoringTable.metrics,
            pluginsByCategory: tables_1.pulseMonitoringTable.pluginsByCategory,
            enable_guard_rails: tables_1.applicationGuardrailsTable.enable_guard_rails,
            input_validators: tables_1.applicationGuardrailsTable.input_validators,
            output_validators: tables_1.applicationGuardrailsTable.output_validators,
        };
        // Fetch applications - show non-archived first, then archived
        const baseQuery = db
            .select(applicationListSelect)
            .from(tables_1.applicationsTable)
            .leftJoin(tables_1.pulseMonitoringTable, (0, drizzle_orm_1.eq)(tables_1.applicationsTable.id, tables_1.pulseMonitoringTable.applicationId))
            .leftJoin(tables_1.applicationGuardrailsTable, (0, drizzle_orm_1.eq)(tables_1.applicationsTable.id, tables_1.applicationGuardrailsTable.applicationId))
            .orderBy(tables_1.applicationsTable.is_archived, // false first, then true
        (0, drizzle_orm_1.desc)(tables_1.applicationsTable.updatedAt))
            .limit(parsedLimit)
            .offset(offset);
        if (whereConditions.length > 0) {
            baseQuery.where((0, drizzle_orm_1.and)(...whereConditions));
        }
        let applicationsRows = await baseQuery;
        if (ensureApplicationId &&
            projectId &&
            !applicationsRows.some((a) => String(a.id) === ensureApplicationId)) {
            const extraConditions = [
                (0, drizzle_orm_1.eq)(tables_1.applicationsTable.id, ensureApplicationId),
                (0, drizzle_orm_1.eq)(tables_1.applicationsTable.projectId, projectId),
            ];
            if (!includeArchived) {
                extraConditions.push((0, drizzle_orm_1.eq)(tables_1.applicationsTable.is_archived, false));
            }
            if (shouldExcludeCustomProviders) {
                extraConditions.push(excludeNonUploadCustomProvidersSql);
            }
            const extraRows = await db
                .select(applicationListSelect)
                .from(tables_1.applicationsTable)
                .leftJoin(tables_1.pulseMonitoringTable, (0, drizzle_orm_1.eq)(tables_1.applicationsTable.id, tables_1.pulseMonitoringTable.applicationId))
                .leftJoin(tables_1.applicationGuardrailsTable, (0, drizzle_orm_1.eq)(tables_1.applicationsTable.id, tables_1.applicationGuardrailsTable.applicationId))
                .where((0, drizzle_orm_1.and)(...extraConditions))
                .limit(1);
            if (extraRows[0]) {
                applicationsRows = [extraRows[0], ...applicationsRows];
            }
        }
        // Total count (respecting archived filter)
        const totalCountQuery = db.select({ count: (0, drizzle_orm_1.sql) `count(*)` }).from(tables_1.applicationsTable);
        const totalCountWhereConditions = [];
        if (projectId) {
            totalCountWhereConditions.push((0, drizzle_orm_1.eq)(tables_1.applicationsTable.projectId, projectId));
        }
        if (search && typeof search === 'string' && search.trim() !== '') {
            totalCountWhereConditions.push((0, drizzle_orm_1.or)((0, drizzle_orm_1.ilike)(tables_1.applicationsTable.name, `%${search}%`), (0, drizzle_orm_1.ilike)(tables_1.applicationsTable.description, `%${search}%`)));
        }
        // Add archived filter if needed
        if (!includeArchived) {
            totalCountWhereConditions.push((0, drizzle_orm_1.eq)(tables_1.applicationsTable.is_archived, false));
        }
        if (shouldExcludeCustomProviders) {
            totalCountWhereConditions.push(excludeNonUploadCustomProvidersSql);
        }
        if (totalCountWhereConditions.length > 0) {
            totalCountQuery.where((0, drizzle_orm_1.and)(...totalCountWhereConditions));
        }
        const totalCount = await totalCountQuery.then((result) => Number(result[0]?.count));
        const applicationIds = applicationsRows.map((a) => a.id);
        const testRuns = await db
            .select({
            id: tables_1.testRunsTable.id,
            application_ids: tables_1.testRunsTable.applicationIds,
            type: tables_1.testRunsTable.type,
        })
            .from(tables_1.testRunsTable)
            .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.sql) `jsonb_array_length("application_ids") > 0`, (0, drizzle_orm_1.sql) `type IN ('eval', 'redteam')`, projectId ? (0, drizzle_orm_1.eq)(tables_1.testRunsTable.projectId, projectId) : (0, drizzle_orm_1.sql) `TRUE`));
        // Count appearances of app_id by type
        const countsMap = {};
        for (const appId of applicationIds) {
            countsMap[appId] = { functionalEvaluationCount: 0, securityEvaluationCount: 0 };
        }
        for (const run of testRuns) {
            const runAppIds = run.application_ids || [];
            for (const appId of runAppIds) {
                if (applicationIds.includes(appId)) {
                    if (run.type === 'eval') {
                        countsMap[appId].functionalEvaluationCount++;
                    }
                    else if (run.type === 'redteam') {
                        countsMap[appId].securityEvaluationCount++;
                    }
                }
            }
        }
        const pulseEntries = applicationIds.length > 0
            ? await db
                .select({
                applicationId: tables_1.pulseMonitoringTable.applicationId,
                metrics: tables_1.pulseMonitoringTable.metrics,
                pluginsByCategory: tables_1.pulseMonitoringTable.pluginsByCategory,
            })
                .from(tables_1.pulseMonitoringTable)
                .where((0, drizzle_orm_1.sql) `application_id = ANY(${drizzle_orm_1.sql.param(applicationIds)})`)
            : [];
        const monitoringMap = {};
        for (const entry of pulseEntries) {
            const { applicationId } = entry;
            monitoringMap[applicationId] = {
                functionalMonitoringEnabled: true,
                securityMonitoringEnabled: true,
            };
        }
        let finalUpgradeMetadata = null;
        let finalGlobalBanner = null;
        if (getRestrictions === 'true') {
            const { upgradeMetadata, isEnterprise, restrictionsData, globalBanner, wallet, thresholds, } = await (0, get_upgrade_meta_1.getUpgradeMetaByOrgId)(orgId);
            if (!isEnterprise && restrictionsData?.applications > 0) {
                const whereConditions = (0, time_1.createTimespanWhereConditions)({
                    table: tables_1.applicationsTable,
                    timeColumn: 'createdAt',
                    orgId: orgId,
                    timespan: restrictionsData?.applications_timespan || 'lifetime',
                });
                const count = await db
                    .select({ count: (0, drizzle_orm_1.sql) `count(*)` })
                    .from(tables_1.applicationsTable)
                    .where(whereConditions)
                    .then((result) => Number(result[0]?.count ?? 0));
                if (count !== 0 && new decimal_js_1.default(count).gte(restrictionsData?.applications ?? 0)) {
                    upgradeMetadata.upgradeRequired = true;
                    upgradeMetadata.topUpRequired = false;
                    upgradeMetadata.upgradeTitle = restriction_message_1.RESTRICTION_MESSAGE.upgrade.title;
                    upgradeMetadata.upgradeMessage = restriction_message_1.RESTRICTION_MESSAGE.upgrade.message;
                    upgradeMetadata.currentPlan = restrictionsData?.currentPlan ?? '';
                    upgradeMetadata.currentPlanId = restrictionsData?.currentPlanId ?? '';
                    globalBanner.show = true;
                    globalBanner.data.content = `You're out of allotted applications with your ${restrictionsData?.currentPlan ?? ''} plan. `;
                    globalBanner.data.type = 'upgrade';
                    globalBanner.data.action = 'Upgrade Now';
                    globalBanner.data.actionType = 'upgrade';
                    globalBanner.data.actionContent = `to create more applications`;
                }
            }
            if (!isEnterprise && new decimal_js_1.default(wallet?.credits ?? 0).gt(0) && new decimal_js_1.default(wallet?.credits ?? 0).lte(thresholds?.walletNotificationThreshold ?? 0)) {
                globalBanner.show = true;
                globalBanner.data.content = `You're low on TRU CREDITS`;
                globalBanner.data.type = 'credits';
                globalBanner.data.action = 'Add TRU CREDITS';
                globalBanner.data.actionType = 'credits';
                globalBanner.data.actionContent = `to continue creating applications`;
            }
            if (!isEnterprise && new decimal_js_1.default(wallet?.credits ?? 0).lte(0)) {
                globalBanner.show = true;
                globalBanner.data.content = `You're low on TRU CREDITS`;
                globalBanner.data.type = 'credits';
                globalBanner.data.action = 'Add TRU CREDITS';
                globalBanner.data.actionType = 'credits';
                globalBanner.data.actionContent = `to continue creating applications`;
            }
            finalUpgradeMetadata = upgradeMetadata;
            finalGlobalBanner = globalBanner;
        }
        // Merge everything
        const enrichedApplications = applicationsRows.map((app) => ({
            ...app,
            ...countsMap[app.id],
            functionalMonitoringEnabled: monitoringMap[app.id]?.functionalMonitoringEnabled ?? false,
            securityMonitoringEnabled: monitoringMap[app.id]?.securityMonitoringEnabled ?? false,
        }));
        res.json({
            success: true,
            data: {
                applications: enrichedApplications,
                pagination: {
                    total: totalCount,
                    page: parsedPage,
                    limit: parsedLimit,
                    totalPages: Math.ceil(totalCount / parsedLimit),
                },
                upgradeMetadata: finalUpgradeMetadata,
                globalBanner: finalGlobalBanner,
            },
        });
    }
    catch (error) {
        logger_1.default.error(`Error fetching applications: ${error}`);
        res.status(500).json({
            success: false,
            message: 'Failed to fetch applications',
        });
    }
};
exports.getApplicationList = getApplicationList;
//# sourceMappingURL=get-application-list.js.map