"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EvalDenormMigrationApi = void 0;
exports.assertClickhouseSchemaAdminSecret = assertClickhouseSchemaAdminSecret;
exports.parseClickhouseEvalDenormMigrateBody = parseClickhouseEvalDenormMigrateBody;
exports.parsePostgresEvalDenormMigrateBody = parsePostgresEvalDenormMigrateBody;
exports.parseEvalDenormBackfillBody = parseEvalDenormBackfillBody;
const logger_1 = __importDefault(require("../../../logger"));
const backfillEvalResultsDenorm_1 = require("../../services/evalResultsClickhouse/backfillEvalResultsDenorm");
const backfillJobStore_1 = require("../../services/evalResultsClickhouse/backfillJobStore");
const clickhouseEvalDenormMigrations_1 = require("../../services/evalResultsClickhouse/clickhouseEvalDenormMigrations");
const postgresEvalDenormMigrations_1 = require("../../services/evalResultsClickhouse/postgresEvalDenormMigrations");
function getBodyRecord(req) {
    const body = req.body;
    if (body !== null && typeof body === 'object' && !Array.isArray(body)) {
        return body;
    }
    return {};
}
function assertClickhouseSchemaAdminSecret(req, res) {
    const expectedSecret = process.env.CLICKHOUSE_SCHEMA_ADMIN_SECRET;
    if (!expectedSecret) {
        return true;
    }
    const provided = req.headers['x-clickhouse-schema-secret'];
    if (provided !== expectedSecret) {
        res.status(403).json({
            success: false,
            message: 'Forbidden: invalid or missing x-clickhouse-schema-secret',
        });
        return false;
    }
    return true;
}
function optionalNumber(body, key) {
    const value = body[key];
    return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
}
function optionalString(body, key) {
    const value = body[key];
    return typeof value === 'string' && value.trim() !== '' ? value.trim() : undefined;
}
function optionalBoolean(body, key) {
    const value = body[key];
    return value === true ? true : value === false ? false : undefined;
}
function optionalStringArray(body, key) {
    const value = body[key];
    if (!Array.isArray(value)) {
        return undefined;
    }
    const strings = value.filter((item) => typeof item === 'string' && item.length > 0);
    return strings.length > 0 ? strings : undefined;
}
/** Parse POST body for ClickHouse eval-denorm DDL migrate. */
function parseClickhouseEvalDenormMigrateBody(body) {
    return {
        dryRun: optionalBoolean(body, 'dryRun'),
        skipOtelIndex: optionalBoolean(body, 'skipOtelIndex'),
        incremental: optionalBoolean(body, 'incremental'),
        devReset: optionalBoolean(body, 'devReset'),
        clearBackfillCheckpoint: optionalBoolean(body, 'clearBackfillCheckpoint'),
        migrationsDir: optionalString(body, 'migrationsDir'),
        only: optionalStringArray(body, 'only'),
    };
}
/** Parse POST body for Postgres eval-denorm DDL migrate. */
function parsePostgresEvalDenormMigrateBody(body) {
    return {
        verifyOnly: optionalBoolean(body, 'verifyOnly'),
    };
}
/** Parse POST body for eval-denorm backfill (targets set by route: ch | pg). */
function parseEvalDenormBackfillBody(body, targets) {
    const readSourceRaw = optionalString(body, 'readSource');
    const readSource = readSourceRaw === 'postgres' || readSourceRaw === 'clickhouse' ? readSourceRaw : undefined;
    return {
        targets,
        readSource,
        batchSize: optionalNumber(body, 'batchSize'),
        maxBatches: optionalNumber(body, 'maxBatches'),
        concurrency: optionalNumber(body, 'concurrency'),
        checkpointEveryBatches: optionalNumber(body, 'checkpointEveryBatches'),
        maxRetries: optionalNumber(body, 'maxRetries'),
        retryInitialDelayMs: optionalNumber(body, 'retryInitialDelayMs'),
        retryMaxDelayMs: optionalNumber(body, 'retryMaxDelayMs'),
        retryBackoffMultiplier: optionalNumber(body, 'retryBackoffMultiplier'),
        projectId: optionalString(body, 'projectId'),
        applicationId: optionalString(body, 'applicationId'),
        dryRun: optionalBoolean(body, 'dryRun'),
        resume: optionalBoolean(body, 'resume'),
        backfillId: optionalString(body, 'backfillId'),
        checkpointPath: optionalString(body, 'checkpointPath'),
        paritySample: optionalNumber(body, 'paritySample'),
        sinceDays: optionalNumber(body, 'sinceDays'),
        allHistory: optionalBoolean(body, 'allHistory'),
        createdAfter: optionalString(body, 'createdAfter'),
        createdBefore: optionalString(body, 'createdBefore'),
    };
}
async function handleMigrateClickhouse(req, res) {
    if (!assertClickhouseSchemaAdminSecret(req, res)) {
        return;
    }
    try {
        const opts = parseClickhouseEvalDenormMigrateBody(getBodyRecord(req));
        logger_1.default.info('API: ClickHouse eval-denorm migrate');
        const result = await (0, clickhouseEvalDenormMigrations_1.runClickhouseEvalDenormMigrations)(opts);
        res.json({ success: true, data: result });
    }
    catch (error) {
        logger_1.default.error(`API: ClickHouse eval-denorm migrate failed: ${error}`);
        res.status(500).json({
            success: false,
            message: 'Failed to migrate ClickHouse eval denorm tables',
            error: error.message,
        });
    }
}
async function handleMigratePostgres(req, res) {
    if (!assertClickhouseSchemaAdminSecret(req, res)) {
        return;
    }
    try {
        const opts = parsePostgresEvalDenormMigrateBody(getBodyRecord(req));
        logger_1.default.info('API: Postgres eval-denorm migrate');
        const result = await (0, postgresEvalDenormMigrations_1.runPostgresEvalDenormMigrations)(opts);
        res.json({ success: true, data: result });
    }
    catch (error) {
        logger_1.default.error(`API: Postgres eval-denorm migrate failed: ${error}`);
        res.status(500).json({
            success: false,
            message: 'Failed to migrate Postgres eval denorm tables',
            error: error.message,
        });
    }
}
async function handleBackfillClickhouse(req, res) {
    if (!assertClickhouseSchemaAdminSecret(req, res)) {
        return;
    }
    try {
        const opts = parseEvalDenormBackfillBody(getBodyRecord(req), 'ch');
        logger_1.default.info('API: ClickHouse eval-denorm backfill');
        const result = await (0, backfillEvalResultsDenorm_1.backfillEvalResultsDenorm)(opts);
        res.json({ success: true, data: result });
    }
    catch (error) {
        logger_1.default.error(`API: ClickHouse eval-denorm backfill failed: ${error}`);
        res.status(500).json({
            success: false,
            message: 'Failed to backfill ClickHouse eval denorm tables',
            error: error.message,
        });
    }
}
async function handleBackfillPostgres(req, res) {
    if (!assertClickhouseSchemaAdminSecret(req, res)) {
        return;
    }
    try {
        const opts = parseEvalDenormBackfillBody(getBodyRecord(req), 'pg');
        logger_1.default.info('API: Postgres eval-denorm backfill');
        const result = await (0, backfillEvalResultsDenorm_1.backfillEvalResultsDenorm)(opts);
        res.json({ success: true, data: result });
    }
    catch (error) {
        logger_1.default.error(`API: Postgres eval-denorm backfill failed: ${error}`);
        res.status(500).json({
            success: false,
            message: 'Failed to backfill Postgres eval denorm tables',
            error: error.message,
        });
    }
}
async function handleGetBackfillStatus(req, res) {
    if (!assertClickhouseSchemaAdminSecret(req, res)) {
        return;
    }
    try {
        const id = typeof req.params.id === 'string' ? req.params.id : '';
        if (!id) {
            res.status(400).json({ success: false, message: 'backfill id is required' });
            return;
        }
        const row = await (0, backfillJobStore_1.getBackfillJobById)(id);
        if (!row) {
            res.status(404).json({ success: false, message: `backfill not found: ${id}` });
            return;
        }
        const children = await (0, backfillJobStore_1.listChildBackfillJobs)(id);
        res.json({
            success: true,
            data: {
                ...(0, backfillJobStore_1.backfillJobToPublicProgress)(row),
                childJobs: children.map((c) => (0, backfillJobStore_1.backfillJobToPublicProgress)(c)),
            },
        });
    }
    catch (error) {
        logger_1.default.error(`API: get backfill status failed: ${error}`);
        res.status(500).json({
            success: false,
            message: 'Failed to load backfill status',
            error: error.message,
        });
    }
}
exports.EvalDenormMigrationApi = {
    migrateClickhouse: handleMigrateClickhouse,
    migratePostgres: handleMigratePostgres,
    backfillClickhouse: handleBackfillClickhouse,
    backfillPostgres: handleBackfillPostgres,
    getBackfillStatus: handleGetBackfillStatus,
};
//# sourceMappingURL=evalDenormApi.js.map