/**
 * Learning System
 *
 * Tracks user decisions and learns preferences over time.
 * Provides contextual suggestions based on historical patterns.
 *
 * Learns from:
 * - decisions.md files (ADRs from each feature)
 * - .morph/project/standards/*.md (project standards)
 * - state.json (feature outcomes and complexity)
 *
 * MORPH-SPEC 3.0 - Sprint 4
 */

import { readFileSync, writeFileSync, existsSync } from 'fs';
import { glob } from 'glob';
import { join } from 'path';
import chalk from 'chalk';

/**
 * Decision Categories
 */
const DECISION_CATEGORIES = {
  uiLibrary: {
    keywords: ['fluent', 'mudblazor', 'radzen', 'ui library', 'component library'],
    options: ['Fluent UI', 'MudBlazor', 'Radzen', 'Custom']
  },
  architecture: {
    keywords: ['cqrs', 'repository', 'mediator', 'clean architecture', 'pattern'],
    options: ['CQRS', 'Repository Pattern', 'Service Layer', 'Direct EF', 'DDD']
  },
  infrastructure: {
    keywords: ['azure', 'sql', 'cosmos', 'storage', 'container apps', 'app service'],
    options: ['Azure SQL', 'Cosmos DB', 'Container Apps', 'App Service', 'Functions', 'Service Bus', 'Storage Queue']
  },
  authentication: {
    keywords: ['auth', 'login', 'identity', 'clerk', 'entra'],
    options: ['Clerk', 'Azure AD/Entra', 'Identity', 'Custom']
  },
  stateManagement: {
    keywords: ['state', 'fluxor', 'redux', 'signal'],
    options: ['Fluxor', 'Blazor State', 'In-Memory', 'API-driven']
  },
  testing: {
    keywords: ['test', 'xunit', 'nunit', 'bunit'],
    options: ['xUnit', 'NUnit', 'bUnit', 'Playwright']
  }
};

/**
 * Learning System Class
 */
export class LearningSystem {
  constructor(projectPath = '.') {
    this.projectPath = projectPath;
    this.knowledgeBasePath = join(projectPath, '.morph', 'knowledge-base.json');
    this.knowledgeBase = this.loadKnowledgeBase();
  }

  /**
   * Load knowledge base from disk
   */
  loadKnowledgeBase() {
    if (existsSync(this.knowledgeBasePath)) {
      try {
        const content = readFileSync(this.knowledgeBasePath, 'utf-8');
        return JSON.parse(content);
      } catch (error) {
        console.warn(chalk.yellow('⚠️  Failed to load knowledge base, creating new one'));
      }
    }

    return this.createEmptyKnowledgeBase();
  }

  /**
   * Create empty knowledge base
   */
  createEmptyKnowledgeBase() {
    return {
      version: '3.0.0',
      lastUpdated: new Date().toISOString(),
      totalDecisions: 0,
      categories: Object.keys(DECISION_CATEGORIES).reduce((acc, category) => {
        acc[category] = {
          total: 0,
          choices: {},
          patterns: []
        };
        return acc;
      }, {}),
      features: [],
      insights: []
    };
  }

  /**
   * Save knowledge base to disk
   */
  saveKnowledgeBase() {
    this.knowledgeBase.lastUpdated = new Date().toISOString();

    try {
      writeFileSync(
        this.knowledgeBasePath,
        JSON.stringify(this.knowledgeBase, null, 2),
        'utf-8'
      );
    } catch (error) {
      console.error(chalk.red('❌ Failed to save knowledge base:', error.message));
    }
  }

  /**
   * Learn from all features in project
   */
  async learnFromProject() {
    console.log(chalk.cyan('🧠 Learning from project history...\n'));

    // Find all decisions.md files
    const decisionFiles = await glob('.morph/project/outputs/*/decisions.md', {
      cwd: this.projectPath
    });

    if (decisionFiles.length === 0) {
      console.log(chalk.yellow('⚠️  No decisions.md files found'));
      return;
    }

    let newDecisions = 0;

    for (const file of decisionFiles) {
      const featureName = file.split('/')[3]; // Extract feature name from path
      const learned = await this.learnFromDecisionFile(file, featureName);
      newDecisions += learned;
    }

    // Generate insights
    this.generateInsights();

    // Save knowledge base
    this.saveKnowledgeBase();

    console.log(chalk.green(`\n✅ Learned ${newDecisions} new decisions from ${decisionFiles.length} features`));
    console.log(chalk.gray(`   Total knowledge: ${this.knowledgeBase.totalDecisions} decisions`));
  }

  /**
   * Learn from single decisions.md file
   */
  async learnFromDecisionFile(filePath, featureName) {
    const content = readFileSync(join(this.projectPath, filePath), 'utf-8');

    // Check if already processed
    if (this.knowledgeBase.features.includes(featureName)) {
      return 0; // Already learned from this feature
    }

    let decisionsLearned = 0;

    // Parse ADRs (Architectural Decision Records)
    const adrs = this.parseADRs(content);

    for (const adr of adrs) {
      const category = this.categorizeDecision(adr);

      if (category) {
        this.recordDecision(category, adr, featureName);
        decisionsLearned++;
      }
    }

    // Mark feature as processed
    this.knowledgeBase.features.push(featureName);

    return decisionsLearned;
  }

  /**
   * Parse ADRs from decisions.md content
   */
  parseADRs(content) {
    const adrs = [];
    const adrPattern = /##\s+ADR-\d+:\s+(.+?)\n([\s\S]*?)(?=##\s+ADR-\d+:|$)/g;
    let match;

    while ((match = adrPattern.exec(content)) !== null) {
      const title = match[1].trim();
      const body = match[2].trim();

      // Extract decision, alternatives, rationale
      const decision = this.extractSection(body, 'Decision|Choice|Selected');
      const alternatives = this.extractSection(body, 'Alternatives|Options|Considered');
      const rationale = this.extractSection(body, 'Rationale|Justification|Why');

      adrs.push({
        title,
        decision,
        alternatives,
        rationale,
        fullText: body
      });
    }

    return adrs;
  }

  /**
   * Extract section from ADR body
   */
  extractSection(body, sectionPattern) {
    const regex = new RegExp(`\\*\\*${sectionPattern}\\*\\*:?\\s*([^*]+)`, 'i');
    const match = body.match(regex);
    return match ? match[1].trim() : '';
  }

  /**
   * Categorize decision into known categories
   */
  categorizeDecision(adr) {
    const text = `${adr.title} ${adr.decision} ${adr.fullText}`.toLowerCase();

    for (const [category, config] of Object.entries(DECISION_CATEGORIES)) {
      for (const keyword of config.keywords) {
        if (text.includes(keyword.toLowerCase())) {
          return category;
        }
      }
    }

    return null; // Uncategorized
  }

  /**
   * Record decision in knowledge base
   */
  recordDecision(category, adr, featureName) {
    const categoryData = this.knowledgeBase.categories[category];

    // Extract chosen option
    const chosen = this.extractChosenOption(adr, category);

    if (chosen) {
      // Increment choice count
      if (!categoryData.choices[chosen]) {
        categoryData.choices[chosen] = { count: 0, features: [], rationales: [] };
      }

      categoryData.choices[chosen].count++;
      categoryData.choices[chosen].features.push(featureName);

      if (adr.rationale) {
        categoryData.choices[chosen].rationales.push(adr.rationale);
      }
    }

    // Store pattern
    categoryData.patterns.push({
      feature: featureName,
      decision: adr.decision,
      rationale: adr.rationale
    });

    categoryData.total++;
    this.knowledgeBase.totalDecisions++;
  }

  /**
   * Extract chosen option from ADR
   */
  extractChosenOption(adr, category) {
    const config = DECISION_CATEGORIES[category];
    const text = `${adr.title} ${adr.decision}`.toLowerCase();

    for (const option of config.options) {
      if (text.includes(option.toLowerCase())) {
        return option;
      }
    }

    return null;
  }

  /**
   * Generate insights from learned patterns
   */
  generateInsights() {
    const insights = [];

    for (const [category, data] of Object.entries(this.knowledgeBase.categories)) {
      if (data.total === 0) continue;

      // Find most common choice
      const sortedChoices = Object.entries(data.choices)
        .sort(([, a], [, b]) => b.count - a.count);

      if (sortedChoices.length > 0) {
        const [topChoice, topData] = sortedChoices[0];
        const percentage = ((topData.count / data.total) * 100).toFixed(0);

        insights.push({
          category,
          type: 'preference',
          insight: `User prefers ${topChoice} for ${category} (${percentage}% of decisions)`,
          confidence: percentage >= 70 ? 'high' : percentage >= 50 ? 'medium' : 'low',
          suggestion: `Suggest ${topChoice} by default for ${category} decisions`,
          evidence: {
            totalDecisions: data.total,
            choiceCount: topData.count,
            features: topData.features
          }
        });
      }

      // Detect patterns (e.g., always use CQRS with complex features)
      if (category === 'architecture' && data.patterns.length > 3) {
        const cqrsPattern = data.patterns.filter(p =>
          p.decision.toLowerCase().includes('cqrs')
        );

        if (cqrsPattern.length > 0) {
          insights.push({
            category,
            type: 'pattern',
            insight: 'User tends to use CQRS for complex features',
            confidence: 'medium',
            suggestion: 'Suggest CQRS when feature complexity is high',
            evidence: {
              occurrences: cqrsPattern.length,
              features: cqrsPattern.map(p => p.feature)
            }
          });
        }
      }
    }

    this.knowledgeBase.insights = insights;
  }

  /**
   * Get suggestion for a category
   */
  getSuggestion(category, context = {}) {
    const categoryData = this.knowledgeBase.categories[category];

    if (!categoryData || categoryData.total === 0) {
      return {
        category,
        suggestion: null,
        confidence: 'none',
        reason: 'No historical data for this category'
      };
    }

    // Find most common choice
    const sortedChoices = Object.entries(categoryData.choices)
      .sort(([, a], [, b]) => b.count - a.count);

    if (sortedChoices.length === 0) {
      return {
        category,
        suggestion: null,
        confidence: 'none',
        reason: 'No choices recorded'
      };
    }

    const [topChoice, topData] = sortedChoices[0];
    const percentage = (topData.count / categoryData.total) * 100;

    const confidence = percentage >= 70 ? 'high' : percentage >= 50 ? 'medium' : 'low';

    return {
      category,
      suggestion: topChoice,
      confidence,
      percentage: percentage.toFixed(0),
      reason: `You chose ${topChoice} in ${topData.count} of ${categoryData.total} previous ${category} decisions`,
      alternatives: sortedChoices.slice(1, 3).map(([choice, data]) => ({
        name: choice,
        count: data.count,
        percentage: ((data.count / categoryData.total) * 100).toFixed(0)
      })),
      recentFeatures: topData.features.slice(-3)
    };
  }

  /**
   * Get all suggestions for current context
   */
  getAllSuggestions(context = {}) {
    const suggestions = {};

    for (const category of Object.keys(DECISION_CATEGORIES)) {
      suggestions[category] = this.getSuggestion(category, context);
    }

    return suggestions;
  }

  /**
   * Format suggestions for console output
   */
  formatSuggestions(suggestions) {
    console.log(chalk.cyan('\n💡 AI Suggestions based on your preferences:\n'));

    for (const [category, suggestion] of Object.entries(suggestions)) {
      if (suggestion.confidence === 'none') continue;

      const confidenceColor = {
        high: chalk.green,
        medium: chalk.yellow,
        low: chalk.gray
      }[suggestion.confidence];

      console.log(confidenceColor(`  ${category}:`));
      console.log(chalk.white(`    → ${suggestion.suggestion} (${suggestion.percentage}% confidence)`));
      console.log(chalk.gray(`      ${suggestion.reason}`));

      if (suggestion.alternatives && suggestion.alternatives.length > 0) {
        console.log(chalk.gray(`      Alternatives: ${suggestion.alternatives.map(a => `${a.name} (${a.percentage}%)`).join(', ')}`));
      }

      console.log('');
    }
  }

  /**
   * Get insights summary
   */
  getInsightsSummary() {
    const insights = this.knowledgeBase.insights;

    if (insights.length === 0) {
      return {
        totalInsights: 0,
        message: 'No insights generated yet. Build more features to learn preferences.'
      };
    }

    const highConfidence = insights.filter(i => i.confidence === 'high');
    const mediumConfidence = insights.filter(i => i.confidence === 'medium');

    return {
      totalInsights: insights.length,
      highConfidence: highConfidence.length,
      mediumConfidence: mediumConfidence.length,
      insights: insights.map(i => ({
        category: i.category,
        insight: i.insight,
        confidence: i.confidence,
        suggestion: i.suggestion
      }))
    };
  }

  /**
   * Format insights for console output
   */
  formatInsights() {
    const summary = this.getInsightsSummary();

    if (summary.totalInsights === 0) {
      console.log(chalk.yellow(`\n⚠️  ${summary.message}\n`));
      return;
    }

    console.log(chalk.cyan(`\n🧠 Learning Insights (${summary.totalInsights} patterns detected):\n`));

    for (const insight of summary.insights) {
      const confidenceEmoji = {
        high: '🟢',
        medium: '🟡',
        low: '🔵'
      }[insight.confidence];

      console.log(`${confidenceEmoji} ${chalk.bold(insight.category)}: ${insight.insight}`);
      console.log(chalk.gray(`   Suggestion: ${insight.suggestion}\n`));
    }
  }

  /**
   * Reset knowledge base (for testing or fresh start)
   */
  reset() {
    this.knowledgeBase = this.createEmptyKnowledgeBase();
    this.saveKnowledgeBase();
    console.log(chalk.yellow('⚠️  Knowledge base reset'));
  }

  /**
   * Export knowledge base for analysis
   */
  export() {
    return {
      ...this.knowledgeBase,
      summary: this.getInsightsSummary()
    };
  }
}

/**
 * Quick functions for imports
 */
export async function learnFromProject(projectPath = '.') {
  const learner = new LearningSystem(projectPath);
  await learner.learnFromProject();
  return learner;
}

export function getSuggestions(projectPath = '.', context = {}) {
  const learner = new LearningSystem(projectPath);
  return learner.getAllSuggestions(context);
}

export function showInsights(projectPath = '.') {
  const learner = new LearningSystem(projectPath);
  learner.formatInsights();
  return learner.getInsightsSummary();
}
