/**
 * Memory File Writer
 *
 * Updates Clawdbot memory files based on analysis results:
 * - feedback-patterns.md — Recurring patterns and anti-patterns
 * - quality-standards.md — Learned quality thresholds per domain
 * - jake-preferences.md — Personal preferences and taste profile
 * - improvement-log.md — What changed and outcomes
 */

import * as fs from "node:fs";
import * as path from "node:path";
import type {
  ThemeCluster,
  CandidateRule,
  DimensionTrend,
  CalibrationCurve,
  ApprovalPatterns,
  Anomaly,
  QualityDimension,
} from "../types.js";

function ensureDir(dir: string): void {
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
}

// ═══════════════════════════════════════════════════════════════
// FEEDBACK PATTERNS
// ═══════════════════════════════════════════════════════════════

export async function writeFeedbackPatterns(
  memoryDir: string,
  data: {
    themes: ThemeCluster[];
    candidateRules: CandidateRule[];
    totalEvents: number;
  }
): Promise<void> {
  ensureDir(memoryDir);
  const filePath = path.join(memoryDir, "feedback-patterns.md");
  const now = new Date().toISOString().split("T")[0];

  let content = `# Feedback Patterns (Auto-Updated)\n`;
  content += `> Last updated: ${now} | Based on ${data.totalEvents} feedback events\n\n`;

  // Recurring themes
  content += `## Recurring Themes (Top ${Math.min(10, data.themes.length)})\n`;
  const topThemes = data.themes.slice(0, 10);
  for (let i = 0; i < topThemes.length; i++) {
    const theme = topThemes[i]!;
    content += `${i + 1}. **${theme.theme}** (mentioned ${theme.occurrences}x)`;
    if (theme.exampleFeedback.length > 0) {
      content += ` — ${theme.exampleFeedback[0]}`;
    }
    content += `\n`;
  }
  content += `\n`;

  // Anti-patterns (from candidate rules for rejected patterns)
  const antiPatternRules = data.candidateRules.filter(
    (r) => r.source === "rejection_analysis" || r.source === "feedback_pattern"
  );
  if (antiPatternRules.length > 0) {
    content += `## Anti-Patterns (Things Consistently Rejected)\n`;
    for (const rule of antiPatternRules.slice(0, 10)) {
      content += `- ${rule.rule} (confidence: ${(rule.confidence * 100).toFixed(0)}%)\n`;
    }
    content += `\n`;
  }

  // Positive patterns
  const positiveThemes = data.themes.filter(
    (t) =>
      t.exampleFeedback.some(
        (f) =>
          f.toLowerCase().includes("great") ||
          f.toLowerCase().includes("nice") ||
          f.toLowerCase().includes("good")
      )
  );
  if (positiveThemes.length > 0) {
    content += `## Positive Patterns (Things Consistently Praised)\n`;
    for (const theme of positiveThemes.slice(0, 5)) {
      content += `- **${theme.theme}** (${theme.occurrences} mentions)\n`;
    }
    content += `\n`;
  }

  // Learned rules
  const highConfRules = data.candidateRules.filter((r) => r.confidence >= 0.8);
  if (highConfRules.length > 0) {
    content += `## Learned Rules (High Confidence)\n`;
    for (const rule of highConfRules) {
      content += `- ${rule.promptInstruction}\n`;
      content += `  - _Confidence: ${(rule.confidence * 100).toFixed(0)}% | Occurrences: ${rule.occurrences} | Domain: ${rule.domain}_\n`;
    }
    content += `\n`;
  }

  fs.writeFileSync(filePath, content, "utf-8");
}

// ═══════════════════════════════════════════════════════════════
// QUALITY STANDARDS
// ═══════════════════════════════════════════════════════════════

export async function writeQualityStandards(
  memoryDir: string,
  data: {
    dimensionTrends: DimensionTrend[];
    calibration: CalibrationCurve;
  }
): Promise<void> {
  ensureDir(memoryDir);
  const filePath = path.join(memoryDir, "quality-standards.md");
  const now = new Date().toISOString().split("T")[0];

  const totalPoints = data.dimensionTrends.reduce(
    (sum, t) => sum + t.dataPoints,
    0
  );
  const confidence =
    totalPoints >= 100 ? "High" : totalPoints >= 30 ? "Medium" : "Low";

  let content = `# Quality Standards (Learned Thresholds)\n`;
  content += `> Last calibrated: ${now} | Confidence: ${confidence} (${totalPoints} data points)\n\n`;

  // Minimum scores (hard gates)
  const withThresholds = data.dimensionTrends.filter(
    (t) => t.minimumThreshold !== undefined
  );
  if (withThresholds.length > 0) {
    content += `## Minimum Acceptable Scores (Hard Gates)\n`;
    content += `| Dimension | Minimum Score | Based On | Avg Score | Trend |\n`;
    content += `|-----------|--------------|----------|-----------|-------|\n`;
    for (const t of withThresholds) {
      content += `| ${t.dimension} | ${t.minimumThreshold} | ${t.dataPoints} reviews | ${t.avgScore} | ${t.trend} (${t.trendDelta > 0 ? "+" : ""}${t.trendDelta}) |\n`;
    }
    content += `\n`;
  }

  // Target scores
  content += `## Dimension Trends\n`;
  content += `| Dimension | Avg Score | Trend | Data Points |\n`;
  content += `|-----------|-----------|-------|-------------|\n`;
  for (const t of data.dimensionTrends) {
    const trendIcon =
      t.trend === "improving" ? "↑" : t.trend === "declining" ? "↓" : "→";
    content += `| ${t.dimension} | ${t.avgScore} | ${trendIcon} ${t.trend} (${t.trendDelta > 0 ? "+" : ""}${t.trendDelta}) | ${t.dataPoints} |\n`;
  }
  content += `\n`;

  // Calibration
  if (data.calibration.buckets.length > 0) {
    content += `## Confidence Calibration\n`;
    content += `Expected Calibration Error: ${(data.calibration.expectedCalibrationError * 100).toFixed(1)}%\n\n`;
    content += `| Raw Confidence | Actual Approval Rate | Correction | Samples |\n`;
    content += `|----------------|---------------------|------------|--------|\n`;
    for (const bucket of data.calibration.buckets) {
      content += `| ${(bucket.rawConfidenceLow * 100).toFixed(0)}%-${(bucket.rawConfidenceHigh * 100).toFixed(0)}% | ${(bucket.avgActualApprovalRate * 100).toFixed(0)}% | ${bucket.correctionDelta > 0 ? "+" : ""}${(bucket.correctionDelta * 100).toFixed(0)}% | ${bucket.sampleCount} |\n`;
    }
    content += `\n`;
  }

  fs.writeFileSync(filePath, content, "utf-8");
}

// ═══════════════════════════════════════════════════════════════
// JAKE'S PREFERENCES
// ═══════════════════════════════════════════════════════════════

export async function writeJakePreferences(
  memoryDir: string,
  data: {
    approvalPatterns: ApprovalPatterns;
    dimensionTrends: DimensionTrend[];
  }
): Promise<void> {
  ensureDir(memoryDir);
  const filePath = path.join(memoryDir, "jake-preferences.md");
  const now = new Date().toISOString().split("T")[0];

  let content = `# Jake's Preferences (Personal Taste Model)\n`;
  content += `> Last updated: ${now}\n\n`;

  // Decision patterns
  content += `## Decision Patterns\n`;
  content += `- **Overall approval rate:** ${(data.approvalPatterns.overall.approvalRate * 100).toFixed(0)}% (${data.approvalPatterns.overall.totalDecisions} decisions)\n`;
  content += `- **Average decision time:** ${(data.approvalPatterns.overall.avgTimeToDecisionMs / 1000).toFixed(1)}s\n\n`;

  // By server type
  const serverTypes = Object.entries(data.approvalPatterns.byServerType);
  if (serverTypes.length > 0) {
    content += `### By Server Type\n`;
    content += `| Server Type | Approved | Rejected | Needs Work | Approval Rate |\n`;
    content += `|-------------|----------|----------|------------|---------------|\n`;
    for (const [type, stats] of serverTypes) {
      content += `| ${type} | ${stats.approved} | ${stats.rejected} | ${stats.needsWork} | ${(stats.approvalRate * 100).toFixed(0)}% |\n`;
    }
    content += `\n`;
  }

  // By stage
  const stages = Object.entries(data.approvalPatterns.byStage);
  if (stages.length > 0) {
    content += `### By Pipeline Stage\n`;
    content += `| Stage | Approval Rate | Avg Time | Count |\n`;
    content += `|-------|--------------|----------|-------|\n`;
    for (const [stage, stats] of stages) {
      content += `| ${stage} | ${(stats.approvalRate * 100).toFixed(0)}% | ${(stats.avgTimeMs / 1000).toFixed(1)}s | ${stats.count} |\n`;
    }
    content += `\n`;
  }

  // Quality dimension preferences (what Jake cares about most)
  const importantDimensions = data.dimensionTrends
    .filter((t) => t.dataPoints >= 5)
    .sort((a, b) => {
      // Dimensions with lower avg scores might indicate stricter standards
      if (a.minimumThreshold && b.minimumThreshold) {
        return b.minimumThreshold - a.minimumThreshold;
      }
      return a.avgScore - b.avgScore;
    });

  if (importantDimensions.length > 0) {
    content += `## Quality Priorities (Most → Least Scrutinized)\n`;
    for (const dim of importantDimensions.slice(0, 8)) {
      const indicator =
        dim.trend === "improving"
          ? "↑"
          : dim.trend === "declining"
            ? "↓"
            : "→";
      content += `- **${dim.dimension}**: avg ${dim.avgScore}/10 ${indicator}`;
      if (dim.minimumThreshold) {
        content += ` (minimum: ${dim.minimumThreshold})`;
      }
      content += `\n`;
    }
    content += `\n`;
  }

  fs.writeFileSync(filePath, content, "utf-8");
}

// ═══════════════════════════════════════════════════════════════
// IMPROVEMENT LOG
// ═══════════════════════════════════════════════════════════════

export async function appendImprovementLog(
  memoryDir: string,
  entry: {
    date: string;
    rulesAdded: CandidateRule[];
    thresholdsChanged: Array<{
      dimension: QualityDimension;
      oldThreshold: number;
      newThreshold: number;
    }>;
    autonomyLevelChanges: Array<{
      taskType: string;
      oldLevel: number;
      newLevel: number;
    }>;
    anomalies: Anomaly[];
  }
): Promise<void> {
  ensureDir(memoryDir);
  const filePath = path.join(memoryDir, "improvement-log.md");

  // Read existing content or create header
  let existing = "";
  if (fs.existsSync(filePath)) {
    existing = fs.readFileSync(filePath, "utf-8");
  } else {
    existing = `# Improvement Log — What Changed and Why\n> Tracks every behavioral change derived from feedback\n\n`;
  }

  // Build new entry
  let newEntry = `## ${entry.date}\n`;

  for (const rule of entry.rulesAdded) {
    newEntry += `- **Rule added:** "${rule.rule}"\n`;
    newEntry += `  - Source: ${rule.occurrences} occurrences via ${rule.source}\n`;
    newEntry += `  - Confidence: ${(rule.confidence * 100).toFixed(0)}%\n`;
  }

  for (const change of entry.thresholdsChanged) {
    newEntry += `- **Threshold adjusted:** ${change.dimension} minimum ${change.oldThreshold}→${change.newThreshold}\n`;
  }

  for (const change of entry.autonomyLevelChanges) {
    newEntry += `- **Autonomy changed:** ${change.taskType} level ${change.oldLevel}→${change.newLevel}\n`;
  }

  for (const anomaly of entry.anomalies) {
    if (anomaly.severity === "warning" || anomaly.severity === "critical") {
      newEntry += `- **⚠️ Anomaly:** ${anomaly.description}\n`;
    }
  }

  newEntry += `\n`;

  // Insert after header, before existing entries
  const headerEnd = existing.indexOf("\n\n") + 2;
  const header = existing.slice(0, headerEnd);
  const body = existing.slice(headerEnd);

  fs.writeFileSync(filePath, header + newEntry + body, "utf-8");
}
