"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ABTestFramework = void 0;
class ABTestFramework {
    tests = new Map();
    counter = 0;
    createTest(name, controlSize, experimentSize) {
        this.counter++;
        const test = {
            id: `ab_${Date.now()}_${this.counter}`,
            name,
            controlGroup: Array.from({ length: controlSize }, (_, i) => `control_${i}`),
            experimentGroup: Array.from({ length: experimentSize }, (_, i) => `experiment_${i}`),
            predictions: [],
            startedAt: new Date().toISOString(),
        };
        this.tests.set(test.id, test);
        return test;
    }
    recordPrediction(testId, predictionId, wasCorrect, group) {
        const test = this.tests.get(testId);
        if (!test)
            return;
        test.predictions.push({ id: predictionId, wasCorrect, group });
    }
    getAccuracy(testId, group) {
        const test = this.tests.get(testId);
        if (!test)
            return 0;
        const groupPredictions = test.predictions.filter((p) => p.group === group);
        if (groupPredictions.length === 0)
            return 0;
        const correct = groupPredictions.filter((p) => p.wasCorrect).length;
        return Math.round((correct / groupPredictions.length) * 100) / 100;
    }
    computeSignificance(testId) {
        const test = this.tests.get(testId);
        if (!test)
            return { pValue: 1, isSignificant: false, winner: 'none' };
        const controlAcc = this.getAccuracy(testId, 'control');
        const experimentAcc = this.getAccuracy(testId, 'experiment');
        const controlN = test.predictions.filter((p) => p.group === 'control').length;
        const experimentN = test.predictions.filter((p) => p.group === 'experiment').length;
        if (controlN < 30 || experimentN < 30) {
            return { pValue: 1, isSignificant: false, winner: 'none' };
        }
        const pooledP = (controlAcc * controlN + experimentAcc * experimentN) / (controlN + experimentN);
        if (pooledP === 0 || pooledP === 1)
            return { pValue: 1, isSignificant: false, winner: 'none' };
        const se = Math.sqrt(pooledP * (1 - pooledP) * (1 / controlN + 1 / experimentN));
        if (se === 0)
            return { pValue: 1, isSignificant: false, winner: 'none' };
        const zScore = (experimentAcc - controlAcc) / se;
        const pValue = 2 * (1 - this.normalCDF(Math.abs(zScore)));
        const isSignificant = pValue < 0.05;
        const winner = isSignificant
            ? (experimentAcc > controlAcc ? 'experiment' : 'control')
            : 'none';
        return {
            pValue: Math.round(pValue * 10000) / 10000,
            isSignificant,
            winner,
        };
    }
    getTest(testId) {
        return this.tests.get(testId);
    }
    getAllTests() {
        return Array.from(this.tests.values());
    }
    getStats(testId) {
        return {
            controlAccuracy: this.getAccuracy(testId, 'control'),
            experimentAccuracy: this.getAccuracy(testId, 'experiment'),
            totalPredictions: this.tests.get(testId)?.predictions.length || 0,
        };
    }
    normalCDF(x) {
        const a1 = 0.254829592;
        const a2 = -0.284496736;
        const a3 = 1.421413741;
        const a4 = -1.453152027;
        const a5 = 1.061405429;
        const p = 0.3275911;
        const sign = x < 0 ? -1 : 1;
        x = Math.abs(x) / Math.sqrt(2);
        const t = 1 / (1 + p * x);
        const y = 1 - (((((a5 * t + a4) * t) + a3) * t + a2) * t + a1) * t * Math.exp(-x * x);
        return 0.5 * (1 + sign * y);
    }
}
exports.ABTestFramework = ABTestFramework;
//# sourceMappingURL=ab-test-framework.js.map