"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runScheduleJobsCron = void 0;
const drizzle_orm_1 = require("drizzle-orm");
const uuid_1 = require("uuid");
const constants_1 = require("../../../constants");
const database_1 = require("../../../database");
const tables_1 = require("../../../database/tables");
const logger_1 = __importDefault(require("../../../logger"));
const sharedFrontend_1 = require("../../../redteam/sharedFrontend");
const callControlPlaneApi_1 = require("../../../util/callContolPlane/callControlPlaneApi");
const get_upgrade_meta_1 = require("../../../util/get-upgrade-meta");
const testSuiteListsConfig_1 = require("../../../util/testSuiteListsConfig");
const restriction_message_1 = require("../../constants/restriction.message");
const scheduleJobsService_1 = require("../../services/scheduleJobsService");
const securityEvalService_1 = require("../../services/securityEvalService");
const testRunService_1 = require("../../services/testRunService");
const runScheduleJobsCron = async (req, res) => {
    try {
        const correlationId = (0, uuid_1.v4)();
        logger_1.default.info(`Schedule jobs cron started with correlation ID: ${correlationId}`);
        // Return response immediately
        res.status(200).json({
            success: true,
            message: 'Schedule jobs cron job started',
            correlationId,
        });
        // Run the actual processing in the background
        setImmediate(async () => {
            try {
                const completedExpiredCount = await scheduleJobsService_1.scheduleJobsService.markEndedScheduleJobsAsCompleted();
                if (completedExpiredCount > 0) {
                    logger_1.default.info(`Cron pre-check completed ${completedExpiredCount} expired schedule job(s)`);
                }
                // Get all due schedule jobs
                const dueJobs = await scheduleJobsService_1.scheduleJobsService.getDueScheduleJobs();
                logger_1.default.info(`Found ${dueJobs.length} due schedule jobs`);
                for (const job of dueJobs) {
                    try {
                        logger_1.default.info(`Processing schedule job ${job.id} (type: ${job.type})`);
                        // Add delay between jobs to avoid overwhelming Cosmos DB
                        if (dueJobs.indexOf(job) > 0) {
                            await new Promise((resolve) => setTimeout(resolve, 1000)); // 1 second delay
                        }
                        const db = await (0, database_1.getDb)();
                        let testRunId = null;
                        if (job.type === constants_1.SCHEDULE_JOB_EVAL_TYPE.FUNCTIONAL_EVAL) {
                            // For functional eval, create test run with library
                            if (job.libraryId && job.applicationId) {
                                try {
                                    // Fetch prompt library with prompts
                                    const [library] = await db
                                        .select()
                                        .from(tables_1.promptsLibraryTable)
                                        .where((0, drizzle_orm_1.eq)(tables_1.promptsLibraryTable.id, job.libraryId))
                                        .limit(1);
                                    if (!library) {
                                        logger_1.default.warn(`Prompt library ${job.libraryId} not found for schedule job ${job.id}`);
                                        continue;
                                    }
                                    // Fetch prompts for the library
                                    const promptRelations = await db
                                        .select({ promptId: tables_1.promptsLibraryPromptsTable.promptId })
                                        .from(tables_1.promptsLibraryPromptsTable)
                                        .where((0, drizzle_orm_1.eq)(tables_1.promptsLibraryPromptsTable.libraryId, job.libraryId));
                                    const promptIds = promptRelations.map((rel) => rel.promptId);
                                    let prompts = [];
                                    if (promptIds.length > 0) {
                                        prompts = await db
                                            .select({
                                            id: tables_1.promptsTable.id,
                                            prompt: tables_1.promptsTable.prompt,
                                            tests: tables_1.promptsTable.tests,
                                            dataset: tables_1.promptsTable.dataset,
                                            createdAt: tables_1.promptsTable.createdAt,
                                            promptType: tables_1.promptsTable.type,
                                            userIntentions: tables_1.promptsTable.userIntentions ?? [],
                                            userProfiles: tables_1.promptsTable.userProfiles ?? [],
                                            openingMessage: tables_1.promptsTable.openingMessage ?? '',
                                            maximumTurns: tables_1.promptsTable.maximumTurns ?? '',
                                            minimumTurns: tables_1.promptsTable.minimumTurns ?? '',
                                            chatStopCriteria: tables_1.promptsTable.chatStopCriteria ?? '',
                                            conversationFlow: tables_1.promptsTable.conversationFlow ?? [],
                                            turns: tables_1.promptsTable.turns ?? [],
                                            conversation_builder_type: tables_1.promptsTable.conversationBuilderType ?? 'call',
                                        })
                                            .from(tables_1.promptsTable)
                                            .where((0, drizzle_orm_1.or)(...promptIds.map((id) => (0, drizzle_orm_1.eq)(tables_1.promptsTable.id, id))));
                                    }
                                    const promptLibrary = {
                                        ...library,
                                        prompts,
                                    };
                                    // Fetch application
                                    const [application] = await db
                                        .select()
                                        .from(tables_1.applicationsTable)
                                        .where((0, drizzle_orm_1.eq)(tables_1.applicationsTable.id, job.applicationId))
                                        .limit(1);
                                    if (!application) {
                                        logger_1.default.warn(`Application ${job.applicationId} not found for schedule job ${job.id}`);
                                        continue;
                                    }
                                    // Generate test suite lists
                                    const testSuiteLists = (0, testSuiteListsConfig_1.generatetestSuiteLists)({
                                        promptLibrary,
                                        applications: [application],
                                        description: '',
                                        defaultTest: {},
                                        scenarios: [],
                                        evaluateOptions: {
                                            cache: false,
                                        },
                                    });
                                    // Run test suite for each prompt
                                    for (const testSuite of testSuiteLists) {
                                        const result = await testRunService_1.testRunService.createTestRun({
                                            evaluateOptions: testSuite.evaluateOptions || {},
                                            applicationIds: [job.applicationId],
                                            libraryId: job.libraryId,
                                            testRunId: testRunId || undefined,
                                            apiKey: 'cron-job',
                                            isCustomProvider: false,
                                            orgId: job.workspaceId || '',
                                            projectId: job.projectId,
                                            testSuite: {
                                                ...testSuite,
                                                ...(testRunId && { testRunId }),
                                            },
                                            token: undefined,
                                            userId: undefined,
                                            userName: undefined,
                                        });
                                        // Check if result is an error
                                        if ('success' in result && result.success === false) {
                                            logger_1.default.error(`Error creating test run for schedule job ${job.id}: ${result.message}`);
                                            // Check if error is due to low TRU credits for starter or professional orgs
                                            if (result.message === restriction_message_1.ERROR_RESTRICTION_MESSAGE.lowCredits.title &&
                                                job.workspaceId) {
                                                try {
                                                    const upgradeMeta = await (0, get_upgrade_meta_1.getUpgradeMetaByOrgId)(job.workspaceId);
                                                    const isStarter = upgradeMeta.isStarter;
                                                    const isProfessional = !upgradeMeta.isEnterprise && !isStarter;
                                                    if (isStarter || isProfessional) {
                                                        await (0, callControlPlaneApi_1.callControlPlane)(`/trusys-emails/schedule-job-paused`, {
                                                            method: 'POST',
                                                            params: {
                                                                orgId: job.workspaceId,
                                                                scheduleJobId: job.id,
                                                                scheduleJobName: job.name || 'Untitled Job',
                                                                orgType: isStarter ? 'Starter' : 'Professional',
                                                                reason: 'Low TRU Credits',
                                                            },
                                                        }, '');
                                                        logger_1.default.info(`Sent schedule job paused email for job ${job.id} due to low credits`);
                                                    }
                                                }
                                                catch (emailError) {
                                                    logger_1.default.error(`Error sending schedule job paused email for job ${job.id}: ${emailError}`);
                                                }
                                            }
                                            continue;
                                        }
                                        // Get testRunId from result
                                        if (!testRunId && 'testRunId' in result) {
                                            testRunId = result.testRunId;
                                        }
                                    }
                                    if (testRunId) {
                                        // updateLastRun will create the mapping and update the schedule
                                        await scheduleJobsService_1.scheduleJobsService.updateLastRun(job.id, testRunId);
                                        logger_1.default.info(`Created functional eval test run ${testRunId} for schedule job ${job.id}`);
                                    }
                                }
                                catch (error) {
                                    logger_1.default.error(`Error creating functional eval for schedule job ${job.id}: ${error}`);
                                }
                            }
                            else {
                                logger_1.default.warn(`Schedule job ${job.id} missing libraryId or applicationId`);
                            }
                        }
                        else if (job.type === constants_1.SCHEDULE_JOB_EVAL_TYPE.SECURITY_EVAL) {
                            // For security eval, create test run with security config
                            if (job.securityConfigId && job.applicationId) {
                                try {
                                    // Fetch security config
                                    const [securityConfig] = await db
                                        .select()
                                        .from(tables_1.securityConfigTable)
                                        .where((0, drizzle_orm_1.eq)(tables_1.securityConfigTable.id, job.securityConfigId))
                                        .limit(1);
                                    if (!securityConfig) {
                                        logger_1.default.warn(`Security config ${job.securityConfigId} not found for schedule job ${job.id}`);
                                        continue;
                                    }
                                    // Fetch application
                                    const [application] = await db
                                        .select()
                                        .from(tables_1.applicationsTable)
                                        .where((0, drizzle_orm_1.eq)(tables_1.applicationsTable.id, job.applicationId))
                                        .limit(1);
                                    if (!application) {
                                        logger_1.default.warn(`Application ${job.applicationId} not found for schedule job ${job.id}`);
                                        continue;
                                    }
                                    // Use security config directly (it should already be in the correct format)
                                    const config = securityConfig.config;
                                    // Create security eval
                                    const result = await securityEvalService_1.securityEvalService.createSecurityEval({
                                        config: (0, sharedFrontend_1.getUnifiedConfig)(config),
                                        force: true,
                                        verbose: false,
                                        delay: 0,
                                        user: {
                                            email: 'system@trusys.ai',
                                        },
                                        projectId: job.projectId,
                                        orgId: job.workspaceId || '',
                                        workspaceId: job.workspaceId || '',
                                        applicationIds: [job.applicationId],
                                        maxConcurrency: 4,
                                        securityConfigId: job.securityConfigId,
                                        isCustomProvider: false,
                                        token: 'cron-job',
                                        userId: undefined,
                                        userName: undefined,
                                    });
                                    // Check if result is an error
                                    if ('success' in result && result.success === false) {
                                        logger_1.default.error(`Error creating security eval for schedule job ${job.id}: ${result.message}`);
                                        // Check if error is due to low TRU credits for starter or professional orgs
                                        if (result.message === restriction_message_1.ERROR_RESTRICTION_MESSAGE.lowCredits.title &&
                                            job.workspaceId) {
                                            try {
                                                const upgradeMeta = await (0, get_upgrade_meta_1.getUpgradeMetaByOrgId)(job.workspaceId);
                                                const isStarter = upgradeMeta.isStarter;
                                                const isProfessional = !upgradeMeta.isEnterprise && !isStarter;
                                                if (isStarter || isProfessional) {
                                                    await (0, callControlPlaneApi_1.callControlPlane)(`/trusys-emails/schedule-job-paused`, {
                                                        method: 'POST',
                                                        params: {
                                                            orgId: job.workspaceId,
                                                            scheduleJobId: job.id,
                                                            scheduleJobName: job.name || 'Untitled Job',
                                                            orgType: isStarter ? 'Starter' : 'Professional',
                                                            reason: 'Low TRU Credits',
                                                        },
                                                    }, '');
                                                    logger_1.default.info(`Sent schedule job paused email for job ${job.id} due to low credits`);
                                                }
                                            }
                                            catch (emailError) {
                                                logger_1.default.error(`Error sending schedule job paused email for job ${job.id}: ${emailError}`);
                                            }
                                        }
                                        continue;
                                    }
                                    if ('testRunId' in result) {
                                        testRunId = result.testRunId;
                                    }
                                    if (testRunId) {
                                        // updateLastRun will create the mapping and update the schedule
                                        await scheduleJobsService_1.scheduleJobsService.updateLastRun(job.id, testRunId);
                                        logger_1.default.info(`Created security eval test run ${testRunId} for schedule job ${job.id}`);
                                    }
                                }
                                catch (error) {
                                    logger_1.default.error(`Error creating security eval for schedule job ${job.id}: ${error}`);
                                }
                            }
                            else {
                                logger_1.default.warn(`Schedule job ${job.id} missing securityConfigId or applicationId`);
                            }
                        }
                        // Even if test run creation failed, update next run time to prevent infinite retries
                        if (!testRunId) {
                            const now = new Date();
                            const nextRunAt = scheduleJobsService_1.scheduleJobsService.computeNextRunAtForJob(job, now);
                            if (nextRunAt) {
                                // Update the job with new next run time
                                await db
                                    .update(tables_1.scheduleJobsTable)
                                    .set({
                                    lastScheduleJobRun: now,
                                    nextRunAt,
                                    updatedAt: now,
                                })
                                    .where((0, drizzle_orm_1.eq)(tables_1.scheduleJobsTable.id, job.id));
                            }
                            logger_1.default.warn(`Test run creation failed for schedule job ${job.id}, but next run time updated`);
                        }
                    }
                    catch (jobError) {
                        logger_1.default.error(`Error processing schedule job ${job.id}: ${jobError}`);
                        // Continue with next job even if one fails
                    }
                }
                logger_1.default.info(`Schedule jobs cron completed successfully. Processed ${dueJobs.length} jobs.`);
            }
            catch (error) {
                logger_1.default.error(`Error in schedule jobs cron background processing: ${error}`);
            }
        });
    }
    catch (error) {
        logger_1.default.error(`Error starting schedule jobs cron: ${error}`);
        if (!res.headersSent) {
            res.status(500).json({
                success: false,
                message: 'Error starting schedule jobs cron',
                error: error.message,
            });
        }
    }
};
exports.runScheduleJobsCron = runScheduleJobsCron;
//# sourceMappingURL=run-schedule-jobs-cron.js.map