import {
  Feature,
  Initiative,
  PrioritizationCriteria,
  PrioritizationResult,
  RICEScore,
  ValueMetrics,
  EffortEstimate
} from './types.js';

export class PrioritizationEngine {
  
  async prioritizeFeatures(
    features: Feature[],
    criteria: PrioritizationCriteria
  ): Promise<PrioritizationResult[]> {
    let results: PrioritizationResult[] = [];

    switch (criteria.method) {
      case 'rice':
        results = await this.riceScoring(features);
        break;
      case 'value-effort':
        results = await this.valueEffortMatrix(features);
        break;
      case 'moscow':
        results = await this.moscowMethod(features);
        break;
      case 'kano':
        results = await this.kanoModel(features);
        break;
      case 'custom':
        results = await this.customWeightedScoring(features, criteria.weights!);
        break;
      default:
        throw new Error(`Unknown prioritization method: ${criteria.method}`);
    }

    // Sort by score descending and assign ranks
    results.sort((a, b) => b.score - a.score);
    results.forEach((result, index) => {
      result.rank = index + 1;
    });

    return results;
  }

  private async riceScoring(features: Feature[]): Promise<PrioritizationResult[]> {
    return features.map(feature => {
      // Calculate RICE components based on feature properties
      const reach = this.estimateReach(feature);
      const impact = this.estimateImpact(feature);
      const confidence = this.estimateConfidence(feature);
      const effort = this.estimateEffort(feature);

      const score = (reach * impact * confidence) / effort;

      const riceBreakdown: RICEScore = {
        reach,
        impact,
        confidence,
        effort,
        score
      };

      return {
        featureId: feature.id,
        method: 'rice',
        score,
        rank: 0, // Will be set later
        rationale: `RICE Score: R=${reach}, I=${impact}, C=${confidence}, E=${effort}`,
        breakdown: riceBreakdown
      };
    });
  }

  private async valueEffortMatrix(features: Feature[]): Promise<PrioritizationResult[]> {
    return features.map(feature => {
      const value = feature.businessValue.score;
      const effort = this.estimateEffort(feature);
      
      // Normalize to 0-100 scale
      const normalizedEffort = Math.min(100, effort * 10);
      
      // Score calculation: high value + low effort = high score
      const score = value * (100 - normalizedEffort) / 100;

      const category = this.getValueEffortCategory(value, normalizedEffort);

      return {
        featureId: feature.id,
        method: 'value-effort',
        score,
        rank: 0,
        rationale: `Value: ${value}/100, Effort: ${normalizedEffort}/100, Category: ${category}`,
        breakdown: { value, effort: normalizedEffort, category }
      };
    });
  }

  private async moscowMethod(features: Feature[]): Promise<PrioritizationResult[]> {
    return features.map(feature => {
      const category = this.getMoscowCategory(feature);
      
      // Assign scores based on MoSCoW categories
      const categoryScores = {
        'must-have': 100,
        'should-have': 75,
        'could-have': 50,
        'wont-have': 25
      };

      const score = categoryScores[category];

      return {
        featureId: feature.id,
        method: 'moscow',
        score,
        rank: 0,
        rationale: `MoSCoW Category: ${category}`,
        breakdown: { category }
      };
    });
  }

  private async kanoModel(features: Feature[]): Promise<PrioritizationResult[]> {
    return features.map(feature => {
      const category = this.getKanoCategory(feature);
      
      // Assign scores based on Kano categories
      const categoryScores = {
        'basic': 90,          // Must-be quality
        'performance': 70,     // One-dimensional quality
        'excitement': 100,     // Attractive quality
        'indifferent': 30,    // Indifferent quality
        'reverse': 10         // Reverse quality
      };

      const score = categoryScores[category];

      return {
        featureId: feature.id,
        method: 'kano',
        score,
        rank: 0,
        rationale: `Kano Category: ${category}`,
        breakdown: { category }
      };
    });
  }

  private async customWeightedScoring(
    features: Feature[],
    weights: NonNullable<PrioritizationCriteria['weights']>
  ): Promise<PrioritizationResult[]> {
    return features.map(feature => {
      // Calculate individual scores (0-100 scale)
      const businessValueScore = feature.businessValue.score;
      const userImpactScore = this.calculateUserImpactScore(feature);
      const strategicAlignmentScore = this.calculateStrategicAlignmentScore(feature);
      const technicalFeasibilityScore = this.calculateTechnicalFeasibilityScore(feature);
      const riskScore = 100 - this.calculateRiskScore(feature); // Invert so lower risk = higher score

      // Apply weights
      const weightedScore = 
        (businessValueScore * weights.businessValue +
         userImpactScore * weights.userImpact +
         strategicAlignmentScore * weights.strategicAlignment +
         technicalFeasibilityScore * weights.technicalFeasibility +
         riskScore * weights.risk) /
        (weights.businessValue + weights.userImpact + 
         weights.strategicAlignment + weights.technicalFeasibility + weights.risk);

      return {
        featureId: feature.id,
        method: 'custom',
        score: weightedScore,
        rank: 0,
        rationale: `Weighted Score: BV=${businessValueScore}, UI=${userImpactScore}, SA=${strategicAlignmentScore}, TF=${technicalFeasibilityScore}, R=${riskScore}`,
        breakdown: {
          businessValue: businessValueScore,
          userImpact: userImpactScore,
          strategicAlignment: strategicAlignmentScore,
          technicalFeasibility: technicalFeasibilityScore,
          risk: riskScore,
          weights
        }
      };
    });
  }

  // Helper methods for RICE scoring
  private estimateReach(feature: Feature): number {
    // Estimate based on business value and user impact
    const impactLevel = feature.businessValue.score;
    
    if (impactLevel > 80) return 10000;  // High reach
    if (impactLevel > 60) return 5000;   // Medium reach
    if (impactLevel > 40) return 1000;   // Low reach
    return 500;                           // Minimal reach
  }

  private estimateImpact(feature: Feature): number {
    // 3 = massive impact, 2 = high, 1 = medium, 0.5 = low, 0.25 = minimal
    const score = feature.businessValue.score;
    
    if (score > 80) return 3;
    if (score > 60) return 2;
    if (score > 40) return 1;
    if (score > 20) return 0.5;
    return 0.25;
  }

  private estimateConfidence(feature: Feature): number {
    // 100% = high confidence, 80% = medium, 50% = low
    // Based on feature status and complexity
    
    if (feature.status === 'approved') return 1.0;
    if (feature.status === 'proposed') return 0.8;
    if (feature.technicalComplexity === 'very-high') return 0.5;
    if (feature.technicalComplexity === 'high') return 0.7;
    return 0.9;
  }

  private estimateEffort(feature: Feature): number {
    // Estimate person-months based on complexity
    const complexityEffort = {
      'low': 0.5,
      'medium': 2,
      'high': 4,
      'very-high': 8
    };
    
    return complexityEffort[feature.technicalComplexity];
  }

  // Helper methods for Value-Effort Matrix
  private getValueEffortCategory(value: number, effort: number): string {
    if (value > 60 && effort < 40) return 'Quick Wins';
    if (value > 60 && effort >= 40) return 'Major Projects';
    if (value <= 60 && effort < 40) return 'Fill-ins';
    return 'Time Sinks';
  }

  // Helper methods for MoSCoW
  private getMoscowCategory(feature: Feature): 'must-have' | 'should-have' | 'could-have' | 'wont-have' {
    const score = feature.businessValue.score;
    const complexity = feature.technicalComplexity;
    
    // High value, manageable complexity = must have
    if (score > 70 && complexity !== 'very-high') return 'must-have';
    
    // High value but complex, or medium value with low complexity = should have
    if ((score > 70 && complexity === 'very-high') || 
        (score > 50 && complexity === 'low')) return 'should-have';
    
    // Medium value = could have
    if (score > 30) return 'could-have';
    
    // Low value = won't have this time
    return 'wont-have';
  }

  // Helper methods for Kano Model
  private getKanoCategory(feature: Feature): 'basic' | 'performance' | 'excitement' | 'indifferent' | 'reverse' {
    // This is a simplified categorization - in practice, you'd survey users
    const value = feature.businessValue.score;
    const description = feature.description.toLowerCase();
    
    // Basic features (must-haves)
    if (description.includes('security') || 
        description.includes('performance') ||
        description.includes('reliability')) {
      return 'basic';
    }
    
    // Excitement features (delighters)
    if (description.includes('ai') || 
        description.includes('innovative') ||
        description.includes('unique')) {
      return 'excitement';
    }
    
    // Performance features (more is better)
    if (value > 60) return 'performance';
    
    // Indifferent features
    if (value < 30) return 'indifferent';
    
    return 'performance'; // Default
  }

  // Helper methods for custom scoring
  private calculateUserImpactScore(feature: Feature): number {
    // Simplified calculation - could be enhanced with actual user data
    return Math.min(100, feature.businessValue.score * 1.2);
  }

  private calculateStrategicAlignmentScore(feature: Feature): number {
    // Check if feature aligns with strategic themes
    // In a real implementation, this would check against company strategy
    return feature.businessValue.score; // Simplified
  }

  private calculateTechnicalFeasibilityScore(feature: Feature): number {
    const feasibilityScores = {
      'low': 90,
      'medium': 70,
      'high': 50,
      'very-high': 30
    };
    
    return feasibilityScores[feature.technicalComplexity];
  }

  private calculateRiskScore(feature: Feature): number {
    // Higher complexity = higher risk
    const riskScores = {
      'low': 20,
      'medium': 40,
      'high': 60,
      'very-high': 80
    };
    
    return riskScores[feature.technicalComplexity];
  }

  // Initiative prioritization
  async prioritizeInitiatives(
    initiatives: Initiative[],
    criteria: PrioritizationCriteria
  ): Promise<PrioritizationResult[]> {
    // Convert initiatives to a format similar to features for prioritization
    const results = initiatives.map(initiative => {
      let score = 0;
      
      // Calculate score based on value metrics and effort
      const valueScore = this.calculateInitiativeValueScore(initiative.value);
      const effortScore = this.calculateInitiativeEffortScore(initiative.effort);
      
      // Simple scoring: value / effort
      score = valueScore / Math.max(1, effortScore);
      
      return {
        featureId: initiative.id, // Using featureId field for compatibility
        method: criteria.method,
        score,
        rank: 0,
        rationale: `Initiative Value: ${valueScore}, Effort: ${effortScore}`,
        breakdown: {
          value: valueScore,
          effort: effortScore,
          valueMetrics: initiative.value,
          effortEstimate: initiative.effort
        }
      };
    });
    
    // Sort and rank
    results.sort((a, b) => b.score - a.score);
    results.forEach((result, index) => {
      result.rank = index + 1;
    });
    
    return results;
  }

  private calculateInitiativeValueScore(value: ValueMetrics): number {
    const impactScores = { low: 25, medium: 50, high: 75, critical: 100 };
    const userImpactScore = impactScores[value.userImpact];
    
    // Normalize financial metrics (assuming millions)
    const revenueScore = Math.min(100, (value.revenueImpact / 1000000) * 20);
    const savingsScore = Math.min(100, (value.costSavings / 1000000) * 30);
    
    // Strategic value is already 1-10, scale to 100
    const strategicScore = value.strategicValue * 10;
    
    // Customer satisfaction impact (NPS scale -100 to 100, normalize to 0-100)
    const satisfactionScore = (value.customerSatisfaction + 100) / 2;
    
    // Weighted average
    return (userImpactScore * 0.3 + 
            revenueScore * 0.2 + 
            savingsScore * 0.2 + 
            strategicScore * 0.2 + 
            satisfactionScore * 0.1);
  }

  private calculateInitiativeEffortScore(effort: EffortEstimate): number {
    const totalWeeks = effort.developmentWeeks + effort.designWeeks + effort.qaWeeks;
    
    // Adjust for confidence
    const confidenceMultiplier = {
      low: 1.5,    // Low confidence = multiply effort by 1.5
      medium: 1.0,
      high: 0.9    // High confidence = slight reduction
    };
    
    return totalWeeks * confidenceMultiplier[effort.confidence];
  }
}