import { Logger } from '../utils/Logger';

export interface TestResult {
  testId: string;
  variations: VariationResult[];
  metrics: {
    [metric: string]: number;
  };
  startDate: string;
  endDate: string;
  sampleSize: number;
  statisticalSignificance: number;
}

export interface VariationResult {
  id: string;
  name: string;
  metrics: {
    [metric: string]: number;
  };
  sampleSize: number;
  conversionRate?: number;
  engagementRate?: number;
  revenuePerUser?: number;
  retentionRate?: number;
}

export interface OptimizationGoal {
  type: 'maximize' | 'minimize';
  metric: string;
  targetValue?: number;
  weight?: number;
}

export interface OptimizationRecommendation {
  recommendedVariation: string;
  confidence: number;
  expectedImprovement: number;
  optimizationActions: OptimizationAction[];
  riskAssessment: 'low' | 'medium' | 'high';
  implementationSteps: string[];
  followUpTests: FollowUpTest[];
}

export interface OptimizationAction {
  id: string;
  description: string;
  priority: 'high' | 'medium' | 'low';
  expectedImpact: number;
  implementationEffort: 'low' | 'medium' | 'high';
}

export interface FollowUpTest {
  testName: string;
  description: string;
  recommendedTiming: string;
  estimatedDuration: number;
}

export class ABTestOptimizationService {
  private logger = new Logger('ABTestOptimizationService');

  async optimizeTest(
    testResult: TestResult,
    optimizationGoals: OptimizationGoal[],
    traceId: string
  ): Promise<OptimizationRecommendation> {
    try {
      this.logger.info('开始优化A/B测试', {
        testId: testResult.testId,
        variationCount: testResult.variations.length,
        traceId
      });

      const bestVariation = this.identifyBestVariation(testResult, optimizationGoals);
      const confidence = this.calculateConfidence(testResult, bestVariation.id);
      const expectedImprovement = this.calculateExpectedImprovement(testResult, bestVariation.id);
      const optimizationActions = this.generateOptimizationActions(testResult, bestVariation, optimizationGoals);
      const risk = this.assessRisk(testResult, bestVariation, optimizationGoals);
      const implementationSteps = this.generateImplementationSteps(optimizationActions);
      const followUpTests = this.recommendFollowUpTests(testResult, bestVariation, optimizationGoals);

      const recommendation: OptimizationRecommendation = {
        recommendedVariation: bestVariation.id,
        confidence,
        expectedImprovement,
        optimizationActions,
        riskAssessment: risk,
        implementationSteps,
        followUpTests
      };

      this.logger.info('A/B测试优化完成', {
        recommendedVariation: bestVariation.id,
        confidence,
        expectedImprovement,
        traceId
      });

      return recommendation;
    } catch (error) {
      this.logger.error('优化A/B测试失败', {
        error: error instanceof Error ? error.message : '未知错误',
        traceId
      });
      throw error;
    }
  }

  private identifyBestVariation(testResult: TestResult, optimizationGoals: OptimizationGoal[]): VariationResult {
    let bestVariation: VariationResult = testResult.variations[0];
    let bestScore = -Infinity;

    testResult.variations.forEach(variation => {
      let score = 0;

      optimizationGoals.forEach(goal => {
        const value = variation.metrics[goal.metric] || 0;
        const weight = goal.weight || 1;

        if (goal.type === 'maximize') {
          score += value * weight;
        } else {
          score += (1 / (value + 0.001)) * weight;
        }
      });

      if (score > bestScore) {
        bestScore = score;
        bestVariation = variation;
      }
    });

    return bestVariation;
  }

  private calculateConfidence(testResult: TestResult, bestVariationId: string): number {
    const bestVariation = testResult.variations.find(v => v.id === bestVariationId);
    if (!bestVariation) return 0;

    const otherVariations = testResult.variations.filter(v => v.id !== bestVariationId);
    const significantWins = otherVariations.filter(other => {
      return this.isStatisticallySignificant(bestVariation!, other);
    });

    return Math.min(1, significantWins.length / otherVariations.length * 0.8 + 0.2);
  }

  private calculateExpectedImprovement(testResult: TestResult, bestVariationId: string): number {
    const bestVariation = testResult.variations.find(v => v.id === bestVariationId);
    if (!bestVariation) return 0;

    const otherVariations = testResult.variations.filter(v => v.id !== bestVariationId);
    if (otherVariations.length === 0) return 0;

    const averagePerformance = otherVariations.reduce((sum, v) => {
      const metricValues = Object.values(v.metrics);
      return sum + metricValues.reduce((sum, val) => sum + val, 0) / metricValues.length;
    }, 0) / otherVariations.length;

    const bestPerformance = Object.values(bestVariation.metrics).reduce((sum, val) => sum + val, 0) / Object.values(bestVariation.metrics).length;

    return (bestPerformance - averagePerformance) / averagePerformance;
  }

  private generateOptimizationActions(
    testResult: TestResult,
    bestVariation: VariationResult,
    optimizationGoals: OptimizationGoal[]
  ): OptimizationAction[] {
    const actions: OptimizationAction[] = [];

    optimizationGoals.forEach(goal => {
      const bestValue = bestVariation.metrics[goal.metric];
      if (bestValue === undefined) return;

      const otherVariations = testResult.variations.filter(v => v.id !== bestVariation.id);
      const averageValue = otherVariations.reduce((sum, v) => sum + (v.metrics[goal.metric] || 0), 0) / otherVariations.length;
      const improvement = (bestValue - averageValue) / averageValue;

      if (Math.abs(improvement) > 0.05) {
        actions.push({
          id: `action_${goal.metric}`,
          description: `优化 ${goal.metric} 指标，采用 ${bestVariation.name} 的策略`,
          priority: Math.abs(improvement) > 0.15 ? 'high' : Math.abs(improvement) > 0.08 ? 'medium' : 'low',
          expectedImpact: Math.abs(improvement),
          implementationEffort: Math.abs(improvement) > 0.15 ? 'medium' : 'low'
        });
      }
    });

    if (actions.length === 0) {
      actions.push({
        id: 'action_no_change',
        description: '保持当前策略，继续监控性能',
        priority: 'low',
        expectedImpact: 0,
        implementationEffort: 'low'
      });
    }

    return actions.sort((a, b) => {
      const priorityOrder = { high: 3, medium: 2, low: 1 };
      return priorityOrder[b.priority] - priorityOrder[a.priority];
    });
  }

  private assessRisk(
    testResult: TestResult,
    bestVariation: VariationResult,
    optimizationGoals: OptimizationGoal[]
  ): 'low' | 'medium' | 'high' {
    let riskScore = 0;

    if (testResult.sampleSize < 500) riskScore += 2;
    else if (testResult.sampleSize < 1000) riskScore += 1;

    if (testResult.statisticalSignificance > 0.1) riskScore += 2;
    else if (testResult.statisticalSignificance > 0.05) riskScore += 1;

    const otherVariations = testResult.variations.filter(v => v.id !== bestVariation.id);
    const closeCompetitors = otherVariations.filter(other => {
      const bestScore = Object.values(bestVariation.metrics).reduce((sum, val) => sum + val, 0);
      const otherScore = Object.values(other.metrics).reduce((sum, val) => sum + val, 0);
      return (otherScore / bestScore) > 0.95;
    });

    if (closeCompetitors.length > 0) riskScore += 1;

    const hasRevenueGoal = optimizationGoals.some(goal => goal.metric.includes('revenue'));
    if (hasRevenueGoal) riskScore += 1;

    if (riskScore >= 5) return 'high';
    if (riskScore >= 3) return 'medium';
    return 'low';
  }

  private generateImplementationSteps(actions: OptimizationAction[]): string[] {
    const steps: string[] = [];

    steps.push('1. 审核优化建议，确认推荐的变体');
    steps.push('2. 制定实施计划，包括时间线和负责人');

    actions.forEach((action, index) => {
      steps.push(`${index + 3}. 实施 ${action.description}（优先级：${action.priority}）`);
    });

    steps.push(`${actions.length + 3}. 监控实施后的性能指标`);
    steps.push(`${actions.length + 4}. 记录实施结果，用于后续分析`);

    return steps;
  }

  private recommendFollowUpTests(
    testResult: TestResult,
    bestVariation: VariationResult,
    optimizationGoals: OptimizationGoal[]
  ): FollowUpTest[] {
    const tests: FollowUpTest[] = [];

    if (optimizationGoals.some(goal => goal.type === 'maximize' && goal.metric.includes('conversion'))) {
      tests.push({
        testName: '转化率优化深度测试',
        description: '进一步优化已识别的高转化率策略',
        recommendedTiming: '2周后',
        estimatedDuration: 7
      });
    }

    if (optimizationGoals.some(goal => goal.type === 'maximize' && goal.metric.includes('revenue'))) {
      tests.push({
        testName: '收入优化扩展测试',
        description: '测试不同定价策略和促销组合',
        recommendedTiming: '3周后',
        estimatedDuration: 14
      });
    }

    if (tests.length === 0) {
      tests.push({
        testName: '性能监控测试',
        description: '持续监控实施后的性能变化',
        recommendedTiming: '1周后',
        estimatedDuration: 7
      });
    }

    return tests;
  }

  private isStatisticallySignificant(variationA: VariationResult, variationB: VariationResult): boolean {
    const metricsA = Object.values(variationA.metrics);
    const metricsB = Object.values(variationB.metrics);

    if (metricsA.length === 0 || metricsB.length === 0) return false;

    const meanA = metricsA.reduce((sum, val) => sum + val, 0) / metricsA.length;
    const meanB = metricsB.reduce((sum, val) => sum + val, 0) / metricsB.length;

    const varianceA = metricsA.reduce((sum, val) => sum + Math.pow(val - meanA, 2), 0) / metricsA.length;
    const varianceB = metricsB.reduce((sum, val) => sum + Math.pow(val - meanB, 2), 0) / metricsB.length;

    const standardError = Math.sqrt(varianceA / metricsA.length + varianceB / metricsB.length);
    const zScore = Math.abs(meanA - meanB) / standardError;

    return zScore > 1.96; // 95% confidence
  }

  async validateOptimization(recommendation: OptimizationRecommendation, traceId: string): Promise<{ valid: boolean; warnings: string[] }> {
    const warnings: string[] = [];

    if (recommendation.confidence < 0.7) {
      warnings.push('置信度较低，建议增加样本量或延长测试时间');
    }

    if (recommendation.expectedImprovement < 0.05) {
      warnings.push('预期改进较小，可能不值得实施');
    }

    if (recommendation.riskAssessment === 'high') {
      warnings.push('风险评估为高，建议谨慎实施');
    }

    if (recommendation.optimizationActions.length === 0) {
      warnings.push('未生成优化行动，建议重新评估测试结果');
    }

    this.logger.info('优化建议验证完成', {
      warningCount: warnings.length,
      traceId
    });

    return {
      valid: warnings.length < 3,
      warnings
    };
  }
}
