"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DataRetentionController = 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 callControlPlaneApi_1 = require("../../../util/callContolPlane/callControlPlaneApi");
const clickhouseService_1 = require("../../services/clickhouseService");
// Table names for ClickHouse queries
const OTEL_TRACES_TABLE_NAME = 'otel_traces';
const EVAL_RESULTS_TABLE_NAME = 'eval_results';
const EVAL_RESULTS_ANALYTICS_TABLE = 'eval_results_analytics';
const EVAL_RESULT_COMPONENTS_TABLE = 'eval_result_components';
// Format dates for ClickHouse compatibility
const formatDateForClickHouse = (date) => {
    return date.toISOString().replace('T', ' ').replace('Z', '');
};
// Helper function to delete eval results for applications from ClickHouse
async function deleteEvalResultsForApplications(applications, retentionDays) {
    if (applications.length === 0) {
        return;
    }
    // Calculate the cutoff date based on retention days
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - retentionDays);
    const cutoffDateStr = formatDateForClickHouse(cutoffDate);
    for (const application of applications) {
        try {
            // Delete eval results from ClickHouse that are older than retention days
            const deleteQuery = `
        ALTER TABLE ${EVAL_RESULTS_TABLE_NAME}
        DELETE WHERE application_id = '${application.id}' 
        AND created_at < '${cutoffDateStr}'
      `;
            await clickhouseService_1.clickHouseService.query(deleteQuery);
            const denormDeleteQuery = `
        ALTER TABLE ${EVAL_RESULTS_ANALYTICS_TABLE}
        DELETE WHERE application_id = '${application.id}'
        AND created_at < '${cutoffDateStr}'
      `;
            await clickhouseService_1.clickHouseService.query(denormDeleteQuery);
            const componentsDeleteQuery = `
        ALTER TABLE ${EVAL_RESULT_COMPONENTS_TABLE}
        DELETE WHERE application_id = '${application.id}'
        AND created_at < '${cutoffDateStr}'
      `;
            await clickhouseService_1.clickHouseService.query(componentsDeleteQuery);
        }
        catch (error) {
            logger_1.default.error(`Error deleting eval results for application ${application.id}: ${error}`);
        }
    }
}
// Helper function to delete traces for applications from ClickHouse
async function deleteTracesForApplications(applications, retentionDays) {
    if (applications.length === 0) {
        return;
    }
    // Calculate the cutoff date based on retention days
    const cutoffDate = new Date();
    cutoffDate.setDate(cutoffDate.getDate() - retentionDays);
    const cutoffDateStr = formatDateForClickHouse(cutoffDate);
    for (const application of applications) {
        try {
            // Delete traces from ClickHouse that are older than retention days
            const deleteQuery = `
        ALTER TABLE ${OTEL_TRACES_TABLE_NAME}
        DELETE WHERE ResourceAttributes['service.name'] = '${application.id}'
        AND Timestamp < '${cutoffDateStr}'
      `;
            await clickhouseService_1.clickHouseService.query(deleteQuery);
        }
        catch (error) {
            logger_1.default.error(`Error deleting traces for application ${application.id}: ${error}`);
        }
    }
}
// Helper function to process organizations for retention cleanup
async function processOrganizationsRetention(organizations) {
    const db = await (0, database_1.getDb)();
    for (const org of organizations) {
        console.log(`Processing organization ${org.id} (${org.name})`);
        // Check if organization has retention_days key
        if (org.retention_days && typeof org.retention_days === 'number') {
            console.log(`Organization ${org.id} (${org.name}) has retention_days: ${org.retention_days}`);
            // Delete traces and eval results for applications in this organization
            try {
                // Get applications for this organization
                const applications = await db
                    .select({
                    id: tables_1.applicationsTable.id,
                    name: tables_1.applicationsTable.name,
                    createdAt: tables_1.applicationsTable.createdAt
                })
                    .from(tables_1.applicationsTable)
                    .where((0, drizzle_orm_1.eq)(tables_1.applicationsTable.workspaceId, org.id));
                // Delete traces for all applications in this organization (older than retention days)
                await deleteTracesForApplications(applications, org.retention_days);
                // Delete eval results for all applications in this organization (older than retention days)
                await deleteEvalResultsForApplications(applications, org.retention_days);
            }
            catch (error) {
                logger_1.default.error(`Error deleting traces for organization ${org.id}: ${error}`);
            }
            // Process database cleanup for this organization
            // Calculate the cutoff date
            const cutoffDate = new Date();
            cutoffDate.setDate(cutoffDate.getDate() - org.retention_days);
            try {
                // Find test runs older than retention_days for this workspace
                const oldTestRuns = await db
                    .select({ id: tables_1.testRunsTable.id, createdAt: tables_1.testRunsTable.createdAt })
                    .from(tables_1.testRunsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(tables_1.testRunsTable.workspaceId, org.id), (0, drizzle_orm_1.lt)(tables_1.testRunsTable.createdAt, cutoffDate)));
                for (const testRun of oldTestRuns) {
                    // Get eval IDs for this test run
                    const testRunEvals = await db
                        .select({ evalId: tables_1.testRunsToEvalsTable.evalId })
                        .from(tables_1.testRunsToEvalsTable)
                        .where((0, drizzle_orm_1.eq)(tables_1.testRunsToEvalsTable.testRunId, testRun.id));
                    // Collect all eval IDs for batch deletion
                    const evalIds = testRunEvals.map(te => te.evalId);
                    if (evalIds.length > 0) {
                        // Delete eval results for all evals in this test run
                        await db
                            .delete(tables_1.evalResultsTable)
                            .where((0, drizzle_orm_1.inArray)(tables_1.evalResultsTable.evalId, evalIds));
                    }
                    // Delete testRunEvals for this test run
                    if (testRunEvals.length > 0) {
                        await db
                            .delete(tables_1.testRunsToEvalsTable)
                            .where((0, drizzle_orm_1.eq)(tables_1.testRunsToEvalsTable.testRunId, testRun.id));
                    }
                    // Archive the test run by setting is_archived to true
                    await db
                        .update(tables_1.testRunsTable)
                        .set({ is_archived: true })
                        .where((0, drizzle_orm_1.eq)(tables_1.testRunsTable.id, testRun.id))
                        .returning({ id: tables_1.testRunsTable.id });
                }
            }
            catch (error) {
                logger_1.default.error(`Error processing retention for org ${org.id}: ${error}`);
            }
        }
        else {
        }
    }
}
const DataRetentionController = {
    async dataRetention(req, res) {
        try {
            const response = await (0, callControlPlaneApi_1.callControlPlane)('/organizations/trusys', {
                method: 'GET',
                params: {
                    page: 1,
                    limit: 500,
                },
            }, '');
            // Check if the API call was successful
            if (response?.error) {
                logger_1.default.error('Organizations API call failed: ' + JSON.stringify(response.error));
                res.status(500).json({
                    success: false,
                    message: 'Organizations API call failed',
                    error: response.error,
                    status: response.status
                });
                return;
            }
            // Process organizations for retention cleanup
            if (response?.response?.organizations) {
                await processOrganizationsRetention(response.response.organizations);
            }
            res.status(200).json({
                success: true,
                message: 'Organizations cron job completed successfully',
                data: response
            });
        }
        catch (error) {
            logger_1.default.error(`Error in organizations cron controller: ${error}`);
            res.status(500).json({
                success: false,
                message: 'Error in organizations cron job',
                error: error.message
            });
        }
    },
};
exports.DataRetentionController = DataRetentionController;
//# sourceMappingURL=index.js.map