/**
 * A/B Testing — Early Stopping Guardrails.
 * Auto-promotion, business hours check, approval requirements, safety limits.
 */

import type { ExperimentDoc, VariantDoc } from './types.js';
import { generateExperimentResult, checkEarlyStopping } from './statistics.js';

export interface GuardrailCheck {
  passed: boolean;
  violation?: string;
  severity: 'info' | 'warning' | 'blocking';
}

/**
 * Run all guardrail checks before allowing early stop or auto-promotion.
 */
export function runGuardrails(
  experiment: ExperimentDoc,
  variants: VariantDoc[],
  daysRunning: number,
  isRevenueImpacting: boolean
): GuardrailCheck[] {
  const checks: GuardrailCheck[] = [];

  // 1. Minimum sample size
  const minSampleCheck = checkMinSampleSize(experiment, variants);
  checks.push(minSampleCheck);

  // 2. Business hours (safety for auto-actions)
  const businessHoursCheck = checkBusinessHours();
  checks.push(businessHoursCheck);

  // 3. Approval requirement
  const approvalCheck = checkApprovalRequired(experiment, isRevenueImpacting);
  checks.push(approvalCheck);

  // 4. Max duration safety limit
  const durationCheck = checkMaxDuration(experiment, daysRunning);
  checks.push(durationCheck);

  // 5. Statistical significance threshold
  const significanceCheck = checkStatisticalSignificance(experiment, variants, daysRunning);
  checks.push(significanceCheck);

  // 6. Variant balance check
  const balanceCheck = checkVariantBalance(variants);
  checks.push(balanceCheck);

  return checks;
}

/**
 * Check minimum sample size per variant.
 */
function checkMinSampleSize(experiment: ExperimentDoc, variants: VariantDoc[]): GuardrailCheck {
  const minRequired = experiment.guardrails.minSampleSizePerVariant;
  const violations: string[] = [];

  for (const v of variants) {
    if (v.stats.participants < minRequired) {
      violations.push(`${v.name}: ${v.stats.participants}/${minRequired}`);
    }
  }

  if (violations.length > 0) {
    return {
      passed: false,
      violation: `Insufficient samples: ${violations.join(', ')}`,
      severity: 'blocking',
    };
  }

  return { passed: true, severity: 'info' };
}

/**
 * Check if current time is within business hours.
 * Prevents auto-promotion during off-hours.
 */
function checkBusinessHours(): GuardrailCheck {
  const now = new Date();
  const hour = now.getHours();
  const day = now.getDay(); // 0 = Sunday, 6 = Saturday

  // Business hours: Monday-Friday, 9 AM - 6 PM
  const isBusinessDay = day >= 1 && day <= 5;
  const isBusinessHour = hour >= 9 && hour < 18;

  if (!isBusinessDay) {
    return {
      passed: false,
      violation: 'Auto-promotion disabled on weekends',
      severity: 'warning',
    };
  }

  if (!isBusinessHour) {
    return {
      passed: false,
      violation: 'Auto-promotion disabled outside business hours (9 AM - 6 PM)',
      severity: 'warning',
    };
  }

  return { passed: true, severity: 'info' };
}

/**
 * Check if approval is required for this experiment.
 */
function checkApprovalRequired(
  experiment: ExperimentDoc,
  isRevenueImpacting: boolean
): GuardrailCheck {
  const requirement = experiment.guardrails.requireApprovalFor;

  if (requirement === 'all') {
    return {
      passed: false,
      violation: 'Approval required: all experiments require manual approval',
      severity: 'blocking',
    };
  }

  if (requirement === 'revenue' && isRevenueImpacting) {
    return {
      passed: false,
      violation: 'Approval required: revenue-impacting experiment',
      severity: 'blocking',
    };
  }

  return { passed: true, severity: 'info' };
}

/**
 * Check max duration safety limit.
 */
function checkMaxDuration(experiment: ExperimentDoc, daysRunning: number): GuardrailCheck {
  const maxDays = experiment.guardrails.maxDurationDays;

  if (daysRunning >= maxDays) {
    return {
      passed: false,
      violation: `Max duration reached: ${daysRunning}/${maxDays} days`,
      severity: 'warning',
    };
  }

  // Warn at 80% of max duration
  if (daysRunning >= maxDays * 0.8) {
    return {
      passed: true,
      violation: `Approaching max duration: ${daysRunning}/${maxDays} days`,
      severity: 'warning',
    };
  }

  return { passed: true, severity: 'info' };
}

/**
 * Check statistical significance threshold.
 */
function checkStatisticalSignificance(
  experiment: ExperimentDoc,
  variants: VariantDoc[],
  daysRunning: number
): GuardrailCheck {
  const earlyStop = checkEarlyStopping(experiment, variants, daysRunning);

  if (earlyStop.shouldStop && earlyStop.confidence >= experiment.guardrails.winnerThreshold / 100) {
    return {
      passed: true,
      violation: `Statistical significance reached: ${(earlyStop.confidence * 100).toFixed(1)}%`,
      severity: 'info',
    };
  }

  return {
    passed: false,
    violation: `Not statistically significant: ${(earlyStop.confidence * 100).toFixed(1)}% < ${experiment.guardrails.winnerThreshold}%`,
    severity: 'blocking',
  };
}

/**
 * Check if variants have balanced traffic allocation.
 */
function checkVariantBalance(variants: VariantDoc[]): GuardrailCheck {
  const participants = variants.map(v => v.stats.participants);
  const total = participants.reduce((a, b) => a + b, 0);

  if (total === 0) {
    return { passed: true, severity: 'info' };
  }

  const ratios = participants.map(p => p / total);
  const expectedRatio = 1 / variants.length;

  // Check if any variant is > 2x or < 0.5x the expected ratio
  const imbalances: string[] = [];
  for (let i = 0; i < variants.length; i++) {
    const ratio = ratios[i];
    if (ratio > expectedRatio * 2) {
      imbalances.push(`${variants[i].name}: ${(ratio * 100).toFixed(1)}% (expected ~${(expectedRatio * 100).toFixed(1)}%)`);
    }
  }

  if (imbalances.length > 0) {
    return {
      passed: false,
      violation: `Traffic imbalance detected: ${imbalances.join(', ')}`,
      severity: 'warning',
    };
  }

  return { passed: true, severity: 'info' };
}

/**
 * Check if all blocking guardrails pass.
 */
export function canAutoPromote(checks: GuardrailCheck[]): boolean {
  return checks.every(c => c.passed || c.severity !== 'blocking');
}

/**
 * Get summary of guardrail violations.
 */
export function getGuardrailViolations(checks: GuardrailCheck[]): string[] {
  return checks
    .filter(c => !c.passed && c.violation)
    .map(c => c.violation!);
}

/**
 * Auto-promotion decision with full guardrail evaluation.
 */
export interface AutoPromotionResult {
  canPromote: boolean;
  winnerVariantId?: string;
  violations: string[];
  warnings: string[];
  result: ReturnType<typeof generateExperimentResult>;
}

export function evaluateAutoPromotion(
  experiment: ExperimentDoc,
  variants: VariantDoc[],
  daysRunning: number,
  isRevenueImpacting: boolean
): AutoPromotionResult {
  const result = generateExperimentResult(experiment, variants, daysRunning);
  const checks = runGuardrails(experiment, variants, daysRunning, isRevenueImpacting);

  const violations = checks
    .filter(c => !c.passed && c.severity === 'blocking')
    .map(c => c.violation!);

  const warnings = checks
    .filter(c => !c.passed && c.severity === 'warning')
    .map(c => c.violation!);

  const canPromote =
    result.status === 'winner_found' &&
    canAutoPromote(checks) &&
    experiment.guardrails.autoStopEnabled;

  return {
    canPromote,
    winnerVariantId: result.winnerVariantId,
    violations,
    warnings,
    result,
  };
}
