"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EVAL_DENORM_CH_BACKFILL_CHECKPOINT_FILES = exports.EVAL_DENORM_CH_DEV_RESET_MIGRATION_FILES = exports.EVAL_DENORM_CH_MIGRATION_FILES = void 0;
exports.shouldUseClickhouseEvalDenormDevReset = shouldUseClickhouseEvalDenormDevReset;
exports.clearEvalDenormChBackfillCheckpoints = clearEvalDenormChBackfillCheckpoints;
exports.dropEvalDenormClickhouseTables = dropEvalDenormClickhouseTables;
exports.runClickhouseEvalDenormMigrations = runClickhouseEvalDenormMigrations;
const node_fs_1 = require("node:fs");
const node_path_1 = __importDefault(require("node:path"));
const logger_1 = __importDefault(require("../../../logger"));
const clickhouseService_1 = require("../clickhouseService");
const backfillScope_1 = require("./backfillScope");
const types_1 = require("./types");
const LEDGER_TABLE = 'eval_denorm_schema_migrations';
const DEFAULT_MIGRATIONS_DIR = node_path_1.default.join(process.cwd(), 'migrations', 'clickhouse');
/** Ordered eval-denorm ClickHouse DDL (idempotent CREATE / ADD COLUMN / INDEX). */
exports.EVAL_DENORM_CH_MIGRATION_FILES = [
    '001_eval_result_components.sql',
    '002_eval_results_analytics.sql',
    '003_otel_traces_trace_id_index.sql',
    '004_add_trace_ids_columns.sql',
];
/**
 * Fresh dev install: base tables + indexes only (trace_ids already in 001/002).
 * Skips incremental 004 ALTERs after a full DROP/CREATE.
 */
exports.EVAL_DENORM_CH_DEV_RESET_MIGRATION_FILES = [
    '001_eval_result_components.sql',
    '002_eval_results_analytics.sql',
    '003_otel_traces_trace_id_index.sql',
];
exports.EVAL_DENORM_CH_BACKFILL_CHECKPOINT_FILES = [
    '.eval-denorm-backfill-ch.checkpoint.json',
    '.eval-denorm-backfill.checkpoint.json',
];
function splitSqlStatements(sql) {
    return sql
        .split(';')
        .map((s) => s.trim())
        .filter((s) => s.length > 0 && !s.startsWith('--'));
}
function isTruthyEnv(value) {
    const v = value?.trim().toLowerCase();
    return v === '1' || v === 'true' || v === 'yes';
}
function isFalsyEnv(value) {
    const v = value?.trim().toLowerCase();
    return v === '0' || v === 'false' || v === 'no';
}
/** Whether migrate should DROP + CREATE instead of ledger iteration. */
function shouldUseClickhouseEvalDenormDevReset(options) {
    if (options?.incremental) {
        return false;
    }
    if (options?.devReset === true) {
        return true;
    }
    if (options?.devReset === false) {
        return false;
    }
    if (isFalsyEnv(process.env.EVAL_DENORM_CH_DEV_RESET)) {
        return false;
    }
    if (isTruthyEnv(process.env.EVAL_DENORM_CH_DEV_RESET)) {
        return true;
    }
    return (0, backfillScope_1.isDevelopmentEnvironment)();
}
function clearEvalDenormChBackfillCheckpoints(cwd = process.cwd()) {
    const cleared = [];
    for (const name of exports.EVAL_DENORM_CH_BACKFILL_CHECKPOINT_FILES) {
        const fullPath = node_path_1.default.join(cwd, name);
        if ((0, node_fs_1.existsSync)(fullPath)) {
            (0, node_fs_1.unlinkSync)(fullPath);
            cleared.push(name);
        }
    }
    return cleared;
}
async function dropEvalDenormClickhouseTables() {
    const tables = [types_1.EVAL_RESULT_COMPONENTS_TABLE, types_1.EVAL_RESULTS_ANALYTICS_TABLE, LEDGER_TABLE];
    for (const table of tables) {
        logger_1.default.info(`ClickHouse eval-denorm dev-reset: DROP TABLE IF EXISTS ${table}`);
        await clickhouseService_1.clickHouseService.command(`DROP TABLE IF EXISTS ${table}`);
    }
    return tables;
}
async function ensureLedgerTable() {
    await clickhouseService_1.clickHouseService.command(`
CREATE TABLE IF NOT EXISTS ${LEDGER_TABLE}
(
    version String,
    applied_at DateTime DEFAULT now()
)
ENGINE = MergeTree
ORDER BY version
`);
}
async function fetchAppliedVersions() {
    try {
        const rows = await clickhouseService_1.clickHouseService.query(`SELECT version FROM ${LEDGER_TABLE} ORDER BY version`);
        return new Set((rows ?? []).map((r) => String(r.version)));
    }
    catch {
        return new Set();
    }
}
async function recordApplied(version) {
    const lit = version.replace(/'/g, "''");
    await clickhouseService_1.clickHouseService.command(`INSERT INTO ${LEDGER_TABLE} (version) VALUES ('${lit}')`);
}
function resolveMigrationFiles(migrationsDir, files, options) {
    let selected = [...files];
    if (options?.skipOtelIndex) {
        selected = selected.filter((f) => f !== '003_otel_traces_trace_id_index.sql');
    }
    if (options?.only && options.only.length > 0) {
        const allowed = new Set(options.only);
        selected = selected.filter((f) => allowed.has(f));
    }
    const onDisk = new Set((0, node_fs_1.readdirSync)(migrationsDir));
    return selected.filter((f) => onDisk.has(f));
}
async function applyMigrationFiles(migrationsDir, files) {
    const applied = [];
    for (const file of files) {
        const fullPath = node_path_1.default.join(migrationsDir, file);
        const sql = (0, node_fs_1.readFileSync)(fullPath, 'utf8');
        const statements = splitSqlStatements(sql);
        for (const statement of statements) {
            logger_1.default.info(`ClickHouse eval-denorm migration ${file}: ${statement.slice(0, 120)}...`);
            await clickhouseService_1.clickHouseService.command(`${statement};`);
        }
        applied.push(file);
    }
    return applied;
}
async function runDevResetMigrations(migrationsDir, options) {
    const files = resolveMigrationFiles(migrationsDir, exports.EVAL_DENORM_CH_DEV_RESET_MIGRATION_FILES, options);
    const result = {
        mode: 'dev-reset',
        applied: [],
        skipped: [],
        pending: files,
    };
    if (options?.dryRun) {
        return result;
    }
    result.droppedTables = await dropEvalDenormClickhouseTables();
    if (options?.clearBackfillCheckpoint !== false) {
        result.checkpointsCleared = clearEvalDenormChBackfillCheckpoints();
    }
    result.applied = await applyMigrationFiles(migrationsDir, files);
    result.pending = [];
    return result;
}
async function runIncrementalMigrations(migrationsDir, options) {
    const files = resolveMigrationFiles(migrationsDir, exports.EVAL_DENORM_CH_MIGRATION_FILES, options);
    const result = {
        mode: 'incremental',
        applied: [],
        skipped: [],
        pending: [],
    };
    if (options?.dryRun) {
        result.pending = files;
        return result;
    }
    await ensureLedgerTable();
    const appliedSet = await fetchAppliedVersions();
    for (const file of files) {
        if (appliedSet.has(file)) {
            result.skipped.push(file);
            continue;
        }
        const appliedForFile = await applyMigrationFiles(migrationsDir, [file]);
        await recordApplied(file);
        result.applied.push(...appliedForFile);
        appliedSet.add(file);
    }
    return result;
}
/**
 * ClickHouse-only DDL pipeline for eval denorm tables (separate from Postgres `db:migrate`).
 *
 * Development: DROP denorm tables + recreate (001–003), clear CH backfill checkpoint.
 * Production/staging: incremental ledger migrations (001–004).
 */
async function runClickhouseEvalDenormMigrations(options) {
    const migrationsDir = options?.migrationsDir ?? DEFAULT_MIGRATIONS_DIR;
    if (shouldUseClickhouseEvalDenormDevReset(options)) {
        return runDevResetMigrations(migrationsDir, options);
    }
    return runIncrementalMigrations(migrationsDir, options);
}
//# sourceMappingURL=clickhouseEvalDenormMigrations.js.map