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

export interface TestGoal {
  type: 'conversion' | 'engagement' | 'revenue' | 'retention';
  metric: string;
  targetValue?: number;
  timeFrame?: string;
}

export interface TestData {
  historicalData?: {
    [key: string]: number;
  };
  audienceSize?: number;
  trafficDistribution?: number;
  currentPerformance?: {
    [key: string]: number;
  };
  constraints?: {
    maxDuration?: number;
    maxTraffic?: number;
    budget?: number;
  };
}

export interface StrategyRecommendation {
  testType: 'A/B' | 'A/B/n' | 'Multivariate';
  sampleSize: number;
  testDuration: number;
  trafficAllocation: number;
  successMetric: string;
  statisticalSignificance: number;
  confidenceLevel: number;
  recommendedVariations: Variation[];
  estimatedImpact: {
    bestCase: number;
    worstCase: number;
    expected: number;
  };
  riskAssessment: 'low' | 'medium' | 'high';
}

export interface Variation {
  id: string;
  name: string;
  description: string;
  changes: {
    [key: string]: any;
  };
  estimatedPerformance: number;
}

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

  async generateStrategy(
    testGoal: TestGoal,
    testData: TestData,
    traceId: string
  ): Promise<StrategyRecommendation> {
    try {
      this.logger.info('开始生成A/B测试策略', {
        testGoal: testGoal.type,
        traceId
      });

      const baseStrategy = this.calculateBaseStrategy(testGoal, testData);
      const variations = this.generateRecommendedVariations(testGoal, testData);
      const impact = this.estimateImpact(testGoal, testData, variations);
      const risk = this.assessRisk(testGoal, testData, baseStrategy);

      const strategy: StrategyRecommendation = {
        ...baseStrategy,
        recommendedVariations: variations,
        estimatedImpact: impact,
        riskAssessment: risk
      };

      this.logger.info('A/B测试策略生成完成', {
        testType: strategy.testType,
        sampleSize: strategy.sampleSize,
        traceId
      });

      return strategy;
    } catch (error) {
      this.logger.error('生成A/B测试策略失败', {
        error: error instanceof Error ? error.message : '未知错误',
        traceId
      });
      throw error;
    }
  }

  private calculateBaseStrategy(testGoal: TestGoal, testData: TestData): Omit<StrategyRecommendation, 'recommendedVariations' | 'estimatedImpact' | 'riskAssessment'> {
    const audienceSize = testData.audienceSize || 10000;
    const trafficAllocation = testData.trafficDistribution || 0.5;
    
    let sampleSize: number;
    let testDuration: number;
    let testType: 'A/B' | 'A/B/n' | 'Multivariate';

    switch (testGoal.type) {
      case 'conversion':
        sampleSize = this.calculateSampleSize(0.05, 0.8, 0.1, 0.15);
        testDuration = Math.ceil(sampleSize / (audienceSize * trafficAllocation / 24));
        testType = 'A/B';
        break;
      case 'engagement':
        sampleSize = this.calculateSampleSize(0.05, 0.8, 0.15, 0.2);
        testDuration = Math.ceil(sampleSize / (audienceSize * trafficAllocation / 24));
        testType = 'A/B/n';
        break;
      case 'revenue':
        sampleSize = this.calculateSampleSize(0.05, 0.9, 0.05, 0.1);
        testDuration = Math.ceil(sampleSize / (audienceSize * trafficAllocation / 24));
        testType = 'A/B';
        break;
      case 'retention':
        sampleSize = this.calculateSampleSize(0.05, 0.8, 0.1, 0.15);
        testDuration = Math.max(7, Math.ceil(sampleSize / (audienceSize * trafficAllocation / 24)));
        testType = 'A/B';
        break;
      default:
        sampleSize = 1000;
        testDuration = 7;
        testType = 'A/B';
    }

    if (testData.constraints?.maxDuration) {
      testDuration = Math.min(testDuration, testData.constraints.maxDuration);
    }

    if (testData.constraints?.maxTraffic) {
      sampleSize = Math.min(sampleSize, Math.floor(audienceSize * testData.constraints.maxTraffic));
    }

    return {
      testType,
      sampleSize,
      testDuration,
      trafficAllocation,
      successMetric: testGoal.metric,
      statisticalSignificance: 0.05,
      confidenceLevel: 0.8
    };
  }

  private generateRecommendedVariations(testGoal: TestGoal, testData: TestData): Variation[] {
    const variations: Variation[] = [];

    switch (testGoal.type) {
      case 'conversion':
        variations.push(
          {
            id: 'v1',
            name: '按钮颜色测试',
            description: '测试不同按钮颜色对转化率的影响',
            changes: { buttonColor: '#FF6B6B' },
            estimatedPerformance: 0.12
          },
          {
            id: 'v2',
            name: '按钮位置测试',
            description: '测试按钮位置对转化率的影响',
            changes: { buttonPosition: 'top' },
            estimatedPerformance: 0.11
          }
        );
        break;
      case 'engagement':
        variations.push(
          {
            id: 'v1',
            name: '内容布局测试',
            description: '测试不同内容布局对用户 engagement 的影响',
            changes: { layout: 'grid' },
            estimatedPerformance: 0.18
          },
          {
            id: 'v2',
            name: '交互元素测试',
            description: '测试添加交互元素对用户 engagement 的影响',
            changes: { interactiveElements: true },
            estimatedPerformance: 0.16
          },
          {
            id: 'v3',
            name: '内容长度测试',
            description: '测试不同内容长度对用户 engagement 的影响',
            changes: { contentLength: 'short' },
            estimatedPerformance: 0.15
          }
        );
        break;
      case 'revenue':
        variations.push(
          {
            id: 'v1',
            name: '定价策略测试',
            description: '测试不同定价策略对 revenue 的影响',
            changes: { pricingStrategy: 'dynamic' },
            estimatedPerformance: 0.08
          },
          {
            id: 'v2',
            name: '促销策略测试',
            description: '测试不同促销策略对 revenue 的影响',
            changes: { promotionStrategy: 'bundle' },
            estimatedPerformance: 0.07
          }
        );
        break;
      case 'retention':
        variations.push(
          {
            id: 'v1',
            name: '个性化推荐测试',
            description: '测试个性化推荐对用户 retention 的影响',
            changes: { personalization: true },
            estimatedPerformance: 0.13
          },
          {
            id: 'v2',
            name: '通知策略测试',
            description: '测试不同通知策略对用户 retention 的影响',
            changes: { notificationStrategy: 'timely' },
            estimatedPerformance: 0.12
          }
        );
        break;
    }

    return variations;
  }

  private estimateImpact(testGoal: TestGoal, testData: TestData, variations: Variation[]): StrategyRecommendation['estimatedImpact'] {
    const currentValue = testData.currentPerformance?.[testGoal.metric] || 0.1;
    const bestVariation = Math.max(...variations.map(v => v.estimatedPerformance));
    const worstVariation = Math.min(...variations.map(v => v.estimatedPerformance));
    const averageVariation = variations.reduce((sum, v) => sum + v.estimatedPerformance, 0) / variations.length;

    return {
      bestCase: bestVariation - currentValue,
      worstCase: worstVariation - currentValue,
      expected: averageVariation - currentValue
    };
  }

  private assessRisk(testGoal: TestGoal, testData: TestData, strategy: Omit<StrategyRecommendation, 'recommendedVariations' | 'estimatedImpact' | 'riskAssessment'>): 'low' | 'medium' | 'high' {
    let riskScore = 0;

    if (strategy.trafficAllocation > 0.8) riskScore += 2;
    else if (strategy.trafficAllocation > 0.5) riskScore += 1;

    if (strategy.testDuration < 3) riskScore += 2;
    else if (strategy.testDuration < 7) riskScore += 1;

    if (testGoal.type === 'revenue') riskScore += 2;
    else if (testGoal.type === 'retention') riskScore += 1;

    if (testData.constraints?.budget && testData.constraints.budget < 1000) riskScore += 1;

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

  private calculateSampleSize(alpha: number, power: number, baseline: number, minimumDetectableEffect: number): number {
    const zAlpha = 1.96; // 95% confidence
    const zBeta = 0.84; // 80% power
    const p1 = baseline;
    const p2 = baseline + minimumDetectableEffect;
    const p = (p1 + p2) / 2;

    const sampleSize = (2 * p * (1 - p) * Math.pow(zAlpha + zBeta, 2)) / Math.pow(p2 - p1, 2);
    return Math.ceil(sampleSize);
  }

  async validateStrategy(strategy: StrategyRecommendation, traceId: string): Promise<{ valid: boolean; errors: string[] }> {
    const errors: string[] = [];

    if (strategy.sampleSize < 100) {
      errors.push('样本量过小，可能导致结果不可靠');
    }

    if (strategy.testDuration < 1) {
      errors.push('测试 duration 必须大于 0');
    }

    if (strategy.trafficAllocation < 0.1) {
      errors.push('流量分配过低，可能导致测试时间过长');
    }

    if (strategy.trafficAllocation > 1) {
      errors.push('流量分配不能超过 100%');
    }

    if (strategy.recommendedVariations.length === 0) {
      errors.push('至少需要一个测试变体');
    }

    this.logger.info('策略验证完成', {
      valid: errors.length === 0,
      errorCount: errors.length,
      traceId
    });

    return {
      valid: errors.length === 0,
      errors
    };
  }
}
