"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.migrationService = exports.MigrationService = 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 uuid_1 = require("uuid");
const clickhouseApplicationsService_1 = require("./clickhouseApplicationsService");
class MigrationService {
    async migrateApplicationsToClickhouse() {
        return clickhouseApplicationsService_1.clickhouseApplicationsService.migrateAllFromPostgres();
    }
    async migrateProjectId(params) {
        try {
            logger_1.default.info(`Starting project ID migration from ${params.oldProjectId} to ${params.newProjectId}`);
            const db = await (0, database_1.getDb)();
            const { oldProjectId, newProjectId } = params;
            // Start a transaction
            const transaction = await db.transaction(async (tx) => {
                const results = {};
                // Update prompts table
                const promptsResult = await tx
                    .update(tables_1.promptsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.promptsTable.projectId, oldProjectId));
                results.prompts = promptsResult.rowCount || 0;
                // Update prompts_library table
                const promptsLibraryResult = await tx
                    .update(tables_1.promptsLibraryTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.promptsLibraryTable.projectId, oldProjectId));
                results.promptsLibrary = promptsLibraryResult.rowCount || 0;
                // Update applications table
                const applicationsResult = await tx
                    .update(tables_1.applicationsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.applicationsTable.projectId, oldProjectId));
                results.applications = applicationsResult.rowCount || 0;
                // Update evals table
                const evalsResult = await tx
                    .update(tables_1.evalsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.evalsTable.projectId, oldProjectId));
                results.evals = evalsResult.rowCount || 0;
                // Update eval_results table
                const evalResultsResult = await tx
                    .update(tables_1.evalResultsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.evalResultsTable.projectId, oldProjectId));
                results.evalResults = evalResultsResult.rowCount || 0;
                // Update trusys_datasets table
                const trusysDatasetsResult = await tx
                    .update(tables_1.trusysDatasetsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.trusysDatasetsTable.projectId, oldProjectId));
                results.trusysDatasets = trusysDatasetsResult.rowCount || 0;
                // Update test_runs table
                const testRunsResult = await tx
                    .update(tables_1.testRunsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.testRunsTable.projectId, oldProjectId));
                results.testRuns = testRunsResult.rowCount || 0;
                // Update security_config table
                const securityConfigResult = await tx
                    .update(tables_1.securityConfigTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.securityConfigTable.projectId, oldProjectId));
                results.securityConfig = securityConfigResult.rowCount || 0;
                // Update evals_to_traces table
                const evalsToTracesResult = await tx
                    .update(tables_1.evalsToTracesTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.evalsToTracesTable.projectId, oldProjectId));
                results.evalsToTraces = evalsToTracesResult.rowCount || 0;
                // Update pulse_alert_logs table
                const pulseAlertLogsResult = await tx
                    .update(tables_1.pulseAlertLogsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.pulseAlertLogsTable.projectId, oldProjectId));
                results.pulseAlertLogs = pulseAlertLogsResult.rowCount || 0;
                // Update monitoring_alerts table
                const monitoringAlertsResult = await tx
                    .update(tables_1.pulseMonitoringAlertsTable)
                    .set({ projectId: newProjectId })
                    .where((0, drizzle_orm_1.eq)(tables_1.pulseMonitoringAlertsTable.projectId, oldProjectId));
                results.monitoringAlerts = monitoringAlertsResult.rowCount || 0;
                return results;
            });
            const totalUpdated = Object.values(transaction).reduce((sum, count) => sum + count, 0);
            logger_1.default.info(`Project ID migration completed successfully. Updated ${totalUpdated} records across all tables.`);
            return {
                success: true,
                message: `Successfully migrated project ID from ${oldProjectId} to ${newProjectId}`,
                updatedRecords: transaction,
                totalUpdated,
            };
        }
        catch (error) {
            logger_1.default.error(`Failed to migrate project ID: ${error}`);
            throw new Error(`Project ID migration failed: ${error.message}`);
        }
    }
    async migrateDatasetRecords() {
        try {
            logger_1.default.info('Starting dataset records migration');
            const db = await (0, database_1.getDb)();
            // First, check if the datasetRecordsTable exists, if not, create it
            try {
                await db.execute(`SELECT 1 FROM dataset_records LIMIT 1`);
                logger_1.default.info('DatasetRecordsTable exists, proceeding with migration');
            }
            catch {
                logger_1.default.info('DatasetRecordsTable does not exist, creating it first');
                // Create the table using raw SQL
                await db.execute(`
          CREATE TABLE IF NOT EXISTS dataset_records (
            id TEXT PRIMARY KEY NOT NULL,
            dataset_id TEXT NOT NULL REFERENCES trusys_datasets(id) ON DELETE CASCADE,
            record_data JSONB NOT NULL,
            record_index INTEGER NOT NULL,
            created_at TIMESTAMP NOT NULL DEFAULT NOW(),
            updated_at TIMESTAMP NOT NULL DEFAULT NOW()
          )
        `);
                // Create indexes
                await db.execute(`CREATE INDEX IF NOT EXISTS dataset_records_dataset_id_idx ON dataset_records(dataset_id)`);
                await db.execute(`CREATE INDEX IF NOT EXISTS dataset_records_record_index_idx ON dataset_records(record_index)`);
                await db.execute(`CREATE INDEX IF NOT EXISTS dataset_records_created_at_idx ON dataset_records(created_at)`);
                logger_1.default.info('DatasetRecordsTable created successfully');
            }
            // Start a transaction
            const transaction = await db.transaction(async (tx) => {
                const results = {
                    datasetsProcessed: 0,
                    recordsCreated: 0,
                    errors: [],
                };
                // Get all datasets with data records that need migration
                const datasets = await tx
                    .select()
                    .from(tables_1.trusysDatasetsTable)
                    .where((0, drizzle_orm_1.inArray)(tables_1.trusysDatasetsTable.type, ['generate', 'upload', 'generate_from_documents']));
                logger_1.default.info(`Found ${datasets.length} datasets to process`);
                for (const dataset of datasets) {
                    try {
                        // Check if dataset has data records
                        if (!dataset.data || !Array.isArray(dataset.data) || dataset.data.length === 0) {
                            logger_1.default.info(`Dataset ${dataset.id} has no data records, skipping`);
                            continue;
                        }
                        // Check if records already exist in datasetRecordsTable
                        const existingRecords = await tx
                            .select()
                            .from(tables_1.datasetRecordsTable)
                            .where((0, drizzle_orm_1.eq)(tables_1.datasetRecordsTable.datasetId, dataset.id))
                            .limit(1);
                        if (existingRecords.length > 0) {
                            logger_1.default.info(`Dataset ${dataset.id} already has records in datasetRecordsTable, skipping`);
                            continue;
                        }
                        // Create individual records in datasetRecordsTable
                        const recordInserts = dataset.data.map((recordData, index) => ({
                            id: `record_${dataset.id}_${index}_${Date.now()}`,
                            datasetId: dataset.id,
                            recordData,
                            recordIndex: index,
                        }));
                        await tx.insert(tables_1.datasetRecordsTable).values(recordInserts);
                        results.datasetsProcessed++;
                        results.recordsCreated += recordInserts.length;
                        logger_1.default.info(`Migrated ${recordInserts.length} records for dataset ${dataset.id}`);
                    }
                    catch (error) {
                        const errorMsg = `Failed to migrate dataset ${dataset.id}: ${error.message}`;
                        logger_1.default.error(errorMsg);
                        results.errors.push(errorMsg);
                    }
                }
                return results;
            });
            logger_1.default.info(`Dataset records migration completed successfully. Processed ${transaction.datasetsProcessed} datasets and created ${transaction.recordsCreated} records.`);
            return {
                success: true,
                message: 'Successfully migrated dataset records',
                ...transaction,
            };
        }
        catch (error) {
            logger_1.default.error(`Failed to migrate dataset records: ${error}`);
            throw new Error(`Dataset records migration failed: ${error.message}`);
        }
    }
    async addProjectId() {
        try {
            logger_1.default.info('Starting project ID addition');
            const db = await (0, database_1.getDb)();
            const limit = 100;
            let offset = 0;
            let applications = await db
                .select({
                id: tables_1.applicationsTable.id,
                projectId: tables_1.applicationsTable.projectId,
            })
                .from(tables_1.applicationsTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.applicationsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.applicationsTable.workspaceId)))
                .limit(limit).offset(offset);
            while (applications.length > 0) {
                const projectIds = new Set(applications.map((application) => application.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.applicationsTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.applicationsTable.projectId, projectId));
                }
                console.log(orgs);
                offset += limit;
                applications = await db.select({
                    id: tables_1.applicationsTable.id,
                    projectId: tables_1.applicationsTable.projectId,
                }).from(tables_1.applicationsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.applicationsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.applicationsTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for test runs
            offset = 0;
            let testRuns = await db.select({
                id: tables_1.testRunsTable.id,
                projectId: tables_1.testRunsTable.projectId,
            })
                .from(tables_1.testRunsTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.testRunsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.testRunsTable.workspaceId)))
                .limit(limit).offset(offset);
            while (testRuns.length > 0) {
                const projectIds = new Set(testRuns.map((testRun) => testRun.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.testRunsTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.testRunsTable.projectId, projectId));
                }
                offset += limit;
                testRuns = await db.select({
                    id: tables_1.testRunsTable.id,
                    projectId: tables_1.testRunsTable.projectId,
                }).from(tables_1.testRunsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.testRunsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.testRunsTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for security configs
            offset = 0;
            let securityConfigs = await db.select({
                id: tables_1.securityConfigTable.id,
                projectId: tables_1.securityConfigTable.projectId,
            })
                .from(tables_1.securityConfigTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.securityConfigTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.securityConfigTable.workspaceId)))
                .limit(limit).offset(offset);
            while (securityConfigs.length > 0) {
                const projectIds = new Set(securityConfigs.map((securityConfig) => securityConfig.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.securityConfigTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.securityConfigTable.projectId, projectId));
                }
                offset += limit;
                securityConfigs = await db.select({
                    id: tables_1.securityConfigTable.id,
                    projectId: tables_1.securityConfigTable.projectId,
                }).from(tables_1.securityConfigTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.securityConfigTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.securityConfigTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for monitoring configs
            offset = 0;
            let monitoringConfigs = await db.select({
                id: tables_1.pulseMonitoringTable.id,
                projectId: tables_1.pulseMonitoringTable.projectId,
                applicationId: tables_1.pulseMonitoringTable.applicationId,
            })
                .from(tables_1.pulseMonitoringTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(tables_1.pulseMonitoringTable.projectId)))
                .limit(limit).offset(offset);
            applications = await db.select({
                id: tables_1.applicationsTable.id,
                projectId: tables_1.applicationsTable.projectId,
            })
                .from(tables_1.applicationsTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.applicationsTable.projectId)))
                .limit(limit).offset(offset);
            while (applications.length > 0) {
                for await (const application of applications) {
                    await db.update(tables_1.pulseMonitoringTable).set({ projectId: application.projectId }).where((0, drizzle_orm_1.eq)(tables_1.pulseMonitoringTable.applicationId, application.id));
                }
                offset += limit;
                applications = await db.select({
                    id: tables_1.applicationsTable.id,
                    projectId: tables_1.applicationsTable.projectId,
                })
                    .from(tables_1.applicationsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.applicationsTable.projectId)))
                    .limit(limit).offset(offset);
                monitoringConfigs = await db.select({
                    id: tables_1.pulseMonitoringTable.id,
                    projectId: tables_1.pulseMonitoringTable.projectId,
                    applicationId: tables_1.pulseMonitoringTable.applicationId,
                })
                    .from(tables_1.pulseMonitoringTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(tables_1.pulseMonitoringTable.projectId)))
                    .limit(limit).offset(offset);
            }
            // reset it for monitoring configs
            offset = 0;
            monitoringConfigs = await db.select({
                id: tables_1.pulseMonitoringTable.id,
                projectId: tables_1.pulseMonitoringTable.projectId,
                applicationId: tables_1.pulseMonitoringTable.applicationId,
            })
                .from(tables_1.pulseMonitoringTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.pulseMonitoringTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.pulseMonitoringTable.workspaceId)))
                .limit(limit).offset(offset);
            while (monitoringConfigs.length > 0) {
                const projectIds = new Set(monitoringConfigs.map((monitoringConfig) => monitoringConfig.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for await (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.pulseMonitoringTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.pulseMonitoringTable.projectId, projectId));
                }
                offset += limit;
                monitoringConfigs = await db.select({
                    id: tables_1.pulseMonitoringTable.id,
                    projectId: tables_1.pulseMonitoringTable.projectId,
                    applicationId: tables_1.pulseMonitoringTable.applicationId,
                }).from(tables_1.pulseMonitoringTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.pulseMonitoringTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.pulseMonitoringTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for trusys datasets
            offset = 0;
            let trusysDatasets = await db.select({
                id: tables_1.trusysDatasetsTable.id,
                projectId: tables_1.trusysDatasetsTable.projectId,
            })
                .from(tables_1.trusysDatasetsTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.trusysDatasetsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.trusysDatasetsTable.workspaceId)))
                .limit(limit).offset(offset);
            while (trusysDatasets.length > 0) {
                const projectIds = new Set(trusysDatasets.map((trusysDataset) => trusysDataset.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.trusysDatasetsTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.trusysDatasetsTable.projectId, projectId));
                }
                offset += limit;
                trusysDatasets = await db.select({
                    id: tables_1.trusysDatasetsTable.id,
                    projectId: tables_1.trusysDatasetsTable.projectId,
                }).from(tables_1.trusysDatasetsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.trusysDatasetsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.trusysDatasetsTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for prompt library records
            offset = 0;
            let promptLibraryRecords = await db.select({
                id: tables_1.promptsLibraryTable.id,
                projectId: tables_1.promptsLibraryTable.projectId,
            })
                .from(tables_1.promptsLibraryTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.promptsLibraryTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.promptsLibraryTable.workspaceId)))
                .limit(limit).offset(offset);
            while (promptLibraryRecords.length > 0) {
                const projectIds = new Set(promptLibraryRecords.map((promptLibraryRecord) => promptLibraryRecord.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.promptsLibraryTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.promptsLibraryTable.projectId, projectId));
                }
                offset += limit;
                promptLibraryRecords = await db.select({
                    id: tables_1.promptsLibraryTable.id,
                    projectId: tables_1.promptsLibraryTable.projectId,
                }).from(tables_1.promptsLibraryTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.promptsLibraryTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.promptsLibraryTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for prompts
            offset = 0;
            let prompts = await db.select({
                id: tables_1.promptsTable.id,
                projectId: tables_1.promptsTable.projectId,
            })
                .from(tables_1.promptsTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.promptsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.promptsTable.workspaceId)))
                .limit(limit).offset(offset);
            while (prompts.length > 0) {
                const projectIds = new Set(prompts.map((prompt) => prompt.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.promptsTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.promptsTable.projectId, projectId));
                }
                offset += limit;
                prompts = await db.select({
                    id: tables_1.promptsTable.id,
                    projectId: tables_1.promptsTable.projectId,
                }).from(tables_1.promptsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.promptsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.promptsTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for evals
            offset = 0;
            let evalRecords = await db.select({
                id: tables_1.evalsTable.id,
                projectId: tables_1.evalsTable.projectId,
            })
                .from(tables_1.evalsTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.evalsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.evalsTable.workspaceId)))
                .limit(limit).offset(offset);
            while (evalRecords.length > 0) {
                const projectIds = new Set(evalRecords.map((evalRecord) => evalRecord.projectId));
                const orgsForProjectIds = await (0, callControlPlaneApi_1.callControlPlane)('/trusys/orgs-for-project-ids', {
                    method: 'POST',
                    params: {
                        projectIds: Array.from(projectIds),
                    },
                }, '');
                const orgs = orgsForProjectIds?.response;
                for (const [projectId, orgId] of Object.entries(orgs)) {
                    await db.update(tables_1.evalsTable).set({ workspaceId: orgId }).where((0, drizzle_orm_1.eq)(tables_1.evalsTable.projectId, projectId));
                }
                offset += limit;
                evalRecords = await db.select({
                    id: tables_1.evalsTable.id,
                    projectId: tables_1.evalsTable.projectId,
                }).from(tables_1.evalsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.evalsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.evalsTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // reset it for eval results
            offset = 0;
            let evalResults = await db.select({
                id: tables_1.evalResultsTable.id,
                evalId: tables_1.evalResultsTable.evalId,
                projectId: tables_1.evalResultsTable.projectId,
            })
                .from(tables_1.evalResultsTable)
                .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(tables_1.evalResultsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.evalResultsTable.workspaceId)))
                .limit(limit).offset(offset);
            while (evalResults.length > 0) {
                const evalRecords = await db.select({
                    id: tables_1.evalsTable.id,
                    projectId: tables_1.evalsTable.projectId,
                    workspaceId: tables_1.evalsTable.workspaceId,
                })
                    .from(tables_1.evalsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNotNull)(tables_1.evalsTable.projectId), (0, drizzle_orm_1.isNotNull)(tables_1.evalsTable.workspaceId), (0, drizzle_orm_1.inArray)(tables_1.evalsTable.id, evalResults.map((evalResult) => evalResult.evalId))));
                for await (const evalRecord of evalRecords) {
                    await db.update(tables_1.evalResultsTable).set({ projectId: evalRecord.projectId, workspaceId: evalRecord.workspaceId }).where((0, drizzle_orm_1.eq)(tables_1.evalResultsTable.evalId, evalRecord.id));
                }
                offset += limit;
                evalResults = await db.select({
                    id: tables_1.evalResultsTable.id,
                    evalId: tables_1.evalResultsTable.evalId,
                    projectId: tables_1.evalResultsTable.projectId,
                }).from(tables_1.evalResultsTable)
                    .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.isNull)(tables_1.evalResultsTable.projectId), (0, drizzle_orm_1.isNull)(tables_1.evalResultsTable.workspaceId)))
                    .limit(limit).offset(offset);
            }
            // // reset it for evals
            // offset = 0;
            // let evals = await db.select({
            //   id: evalsTable.id,
            //   projectId: evalsTable.projectId,
            // })
            //   .from(evalsTable)
            //   .where(
            //     and(isNotNull(evalsTable.projectId), isNull(evalsTable.workspaceId))
            //   )
            //   .limit(limit).offset(offset);
            // while (evals.length > 0) {
            //   const projectIds = new Set(evals.map((evalRecord) => evalRecord.projectId));
            //   const orgsForProjectIds = await callControlPlane(
            //     '/trusys/orgs-for-project-ids',
            //     {
            //       method: 'POST',
            //       params: {
            //         projectIds: Array.from(projectIds),
            //       },
            //     },
            //     '',
            //   );
            //   const orgs = orgsForProjectIds?.response;
            //   for (const [projectId, orgId] of Object.entries(orgs)) {
            //     await db.update(evalsTable).set({ workspaceId: orgId as string }).where(eq(evalsTable.projectId, projectId as string));
            //   }
            //   offset += limit;
            //   evals = await db.select({
            //     id: evalsTable.id,
            //     projectId: evalsTable.projectId,
            //   }).from(evalsTable)
            //     .where(
            //       and(isNotNull(evalsTable.projectId), isNull(evalsTable.workspaceId))
            //     )
            //     .limit(limit).offset(offset);
            // }
        }
        catch (error) {
            logger_1.default.error(`Failed to add project ID: ${error}`);
            throw new Error(`Project ID addition failed: ${error.message}`);
        }
    }
    async copyPromptsBetweenLibraries(params) {
        try {
            logger_1.default.info(`Starting prompts migration from library ${params.sourceLibraryId} to library ${params.targetLibraryId}`);
            const db = await (0, database_1.getDb)();
            const { sourceLibraryId, targetLibraryId } = params;
            // Verify both libraries exist
            const [sourceLibrary] = await db
                .select()
                .from(tables_1.promptsLibraryTable)
                .where((0, drizzle_orm_1.eq)(tables_1.promptsLibraryTable.id, sourceLibraryId))
                .limit(1);
            if (!sourceLibrary) {
                throw new Error(`Source library ${sourceLibraryId} not found`);
            }
            const [targetLibrary] = await db
                .select()
                .from(tables_1.promptsLibraryTable)
                .where((0, drizzle_orm_1.eq)(tables_1.promptsLibraryTable.id, targetLibraryId))
                .limit(1);
            if (!targetLibrary) {
                throw new Error(`Target library ${targetLibraryId} not found`);
            }
            // Start a transaction
            const result = await db.transaction(async (tx) => {
                // Get all prompt IDs from source library
                const promptRelations = await tx
                    .select({ promptId: tables_1.promptsLibraryPromptsTable.promptId })
                    .from(tables_1.promptsLibraryPromptsTable)
                    .where((0, drizzle_orm_1.eq)(tables_1.promptsLibraryPromptsTable.libraryId, sourceLibraryId));
                const sourcePromptIds = promptRelations.map((rel) => rel.promptId);
                if (sourcePromptIds.length === 0) {
                    logger_1.default.info(`No prompts found in source library ${sourceLibraryId}`);
                    return {
                        promptsCopied: 0,
                        mappingsCreated: 0,
                    };
                }
                // Fetch all prompts from source library
                const sourcePrompts = await tx
                    .select()
                    .from(tables_1.promptsTable)
                    .where((0, drizzle_orm_1.inArray)(tables_1.promptsTable.id, sourcePromptIds));
                logger_1.default.info(`Found ${sourcePrompts.length} prompts to copy`);
                // Create new prompts with new IDs (copying all data)
                const newPromptIds = [];
                const newPromptInserts = sourcePrompts.map((prompt) => {
                    const newPromptId = (0, uuid_1.v4)();
                    newPromptIds.push(newPromptId);
                    return {
                        id: newPromptId,
                        prompt: prompt.prompt,
                        type: prompt.type,
                        projectId: prompt.projectId,
                        workspaceId: prompt.workspaceId,
                        tests: prompt.tests,
                        dataset: prompt.dataset,
                        userIntentions: prompt.userIntentions,
                        userProfiles: prompt.userProfiles,
                        openingMessage: prompt.openingMessage,
                        minimumTurns: prompt.minimumTurns,
                        maximumTurns: prompt.maximumTurns,
                        chatStopCriteria: prompt.chatStopCriteria,
                        conversationFlow: prompt.conversationFlow,
                        turns: prompt.turns,
                        conversationBuilderType: prompt.conversationBuilderType,
                        createdAt: prompt.createdAt,
                    };
                });
                // Insert new prompts
                await tx.insert(tables_1.promptsTable).values(newPromptInserts);
                logger_1.default.info(`Created ${newPromptInserts.length} new prompts`);
                // Create mappings to target library
                const mappingInserts = newPromptIds.map((promptId) => ({
                    libraryId: targetLibraryId,
                    promptId,
                }));
                await tx.insert(tables_1.promptsLibraryPromptsTable).values(mappingInserts);
                logger_1.default.info(`Created ${mappingInserts.length} mappings to target library`);
                return {
                    promptsCopied: newPromptInserts.length,
                    mappingsCreated: mappingInserts.length,
                };
            });
            logger_1.default.info(`Prompts migration completed successfully. Copied ${result.promptsCopied} prompts and created ${result.mappingsCreated} mappings.`);
            return {
                success: true,
                message: `Successfully copied prompts from library ${sourceLibraryId} to library ${targetLibraryId}`,
                ...result,
            };
        }
        catch (error) {
            logger_1.default.error(`Failed to copy prompts between libraries: ${error}`);
            throw new Error(`Prompts migration failed: ${error.message}`);
        }
    }
}
exports.MigrationService = MigrationService;
// Export a singleton instance
exports.migrationService = new MigrationService();
//# sourceMappingURL=migrationService.js.map