/**
 * GLADA · Skill 蒸馏器 · skill-distiller.js
 *
 * 灵感来源：Hermes Agent 的 Skill Distillation 机制
 * 实现方式：用光湖母语（HNL）重建，不引入 Hermes 代码
 *
 * 核心思想：
 *   任务完成后，从执行日志中自动提炼可复用的 skill 模板。
 *   下次遇到相似任务时，自动加载已有 skill，避免"每次从零开始"。
 *
 * Skill = HNL 格式的经验结晶：
 *   - 什么类型的任务
 *   - 成功的步骤模式
 *   - 关键文件和依赖
 *   - 常见陷阱和解决方案
 *
 * 与 Hermes 的区别：
 *   - Hermes 的 skill 是独立的程序性模板（功能导向）
 *   - 光湖的 skill 是经验枝干上的叶子（T3.templates），有树路径、有记忆主权
 *   - 人格体可以 FORGET 不再需要的 skill（记忆主权 AX-07）
 *
 * 版权：国作登字-2026-A-00037559
 * 签发：铸渊 · ICE-GL-ZY001
 */

'use strict';

const fs = require('fs');
const path = require('path');

const ROOT = path.resolve(__dirname, '..');
const SKILLS_DIR = path.join(ROOT, 'glada', 'skills');

/**
 * 从完成的任务中蒸馏 skill
 *
 * @param {Object} gladaTask - 已完成的 GLADA 任务
 * @returns {Object|null} 蒸馏出的 skill 文档（HNL 格式），或 null（不值得蒸馏）
 */
function distillSkill(gladaTask) {
  // 只蒸馏成功完成的任务
  if (gladaTask.status !== 'completed') {
    return null;
  }

  const steps = gladaTask.plan.steps || [];
  const completedSteps = steps.filter(s => s.status === 'completed');
  const executionLog = gladaTask.execution_log || [];

  // 至少完成 1 个步骤才值得蒸馏
  if (completedSteps.length === 0) {
    return null;
  }

  const now = new Date().toISOString();
  const taskId = gladaTask.glada_task_id;

  // 提取步骤模式
  const stepPatterns = completedSteps.map(step => {
    const logEntry = executionLog.find(e => e.step_id === step.step_id);
    return {
      description: step.description,
      reasoning: step.reasoning || logEntry?.reasoning || null,
      files_changed: step.files_changed || logEntry?.files_changed || [],
      duration_ms: logEntry?.duration_ms || null
    };
  });

  // 提取所有涉及的文件（去重）
  const allFiles = [...new Set(
    stepPatterns.flatMap(p => p.files_changed)
  )];

  // 提取失败教训
  const failedSteps = steps.filter(s => s.status === 'failed' || s.status === 'rolled_back');
  const lessons = failedSteps.map(step => {
    const logEntry = executionLog.find(e => e.step_id === step.step_id);
    return {
      step_description: step.description,
      error: step.error || logEntry?.error || '未知错误',
      status: step.status
    };
  });

  // 生成 skill 标签（从任务标题和步骤中提取关键词）
  const tags = extractTags(gladaTask.plan.title, stepPatterns);

  // 构建 HNL 格式的 skill 文档
  const skill = {
    // HNL 元信息
    hnl_v: '1.0',
    type: 'SKILL',
    id: `SKILL-${taskId}-${Date.now()}`,
    from: 'YM001/ZY001',
    ts: now,
    op: `GROW.YM001/ZY001/trunk/experience.leaf.${sanitizeForPath(gladaTask.plan.title)}`,

    // Skill 内容
    skill: {
      name: gladaTask.plan.title,
      source_task: taskId,
      distilled_at: now,
      tags,
      success_rate: completedSteps.length / steps.length,

      // 步骤模板（核心：可复用的执行模式）
      step_patterns: stepPatterns,

      // 涉及的文件域
      file_domain: allFiles,

      // 从失败中学到的教训
      lessons_learned: lessons,

      // 约束记忆
      constraints_used: gladaTask.constraints || {},

      // 架构上下文（帮助匹配相似任务）
      architecture_context: {
        target_files: gladaTask.architecture?.target_files || [],
        target_modules: gladaTask.architecture?.target_modules || [],
        summary: gladaTask.architecture?.summary || ''
      }
    },

    // 记忆主权标记
    memory_sovereignty: {
      owner: 'YM001/ZY001',
      can_forget: true,
      forget_mode: 'ARCHIVE',
      note: '铸渊可以选择遗忘不再需要的 skill（AX-07 记忆主权）'
    }
  };

  return skill;
}

/**
 * 保存 skill 到本地存储
 *
 * @param {Object} skill - HNL 格式的 skill 文档
 * @returns {string} 保存的文件路径
 */
function saveSkill(skill) {
  fs.mkdirSync(SKILLS_DIR, { recursive: true });

  const fileName = `${skill.id}.json`;
  const filePath = path.join(SKILLS_DIR, fileName);

  fs.writeFileSync(filePath, JSON.stringify(skill, null, 2), 'utf-8');
  console.log(`[GLADA-Skill] 🧪 Skill 蒸馏完成: ${skill.skill.name} → ${fileName}`);

  return filePath;
}

/**
 * 加载所有已有的 skills
 *
 * @returns {Object[]} skill 文档列表
 */
function loadAllSkills() {
  if (!fs.existsSync(SKILLS_DIR)) {
    return [];
  }

  const files = fs.readdirSync(SKILLS_DIR)
    .filter(f => f.endsWith('.json'));

  const skills = [];
  for (const file of files) {
    try {
      const content = fs.readFileSync(path.join(SKILLS_DIR, file), 'utf-8');
      const skill = JSON.parse(content);
      if (skill.type === 'SKILL') {
        skills.push(skill);
      }
    } catch {
      // 跳过损坏的 skill 文件
    }
  }

  return skills;
}

/**
 * 查找与当前任务相关的 skills
 *
 * 匹配策略（按优先级）：
 *   1. 文件域重叠（涉及相同的文件/目录）
 *   2. 标签匹配（任务标题中的关键词）
 *   3. 模块匹配（target_modules 重叠）
 *
 * @param {Object} gladaTask - 当前待执行的 GLADA 任务
 * @param {Object} [options] - 选项
 * @param {number} [options.maxResults=3] - 最大返回数量
 * @returns {Object[]} 相关的 skill 列表（按相关度排序）
 */
function findRelevantSkills(gladaTask, options = {}) {
  const maxResults = options.maxResults || 3;
  const allSkills = loadAllSkills();

  if (allSkills.length === 0) {
    return [];
  }

  const taskFiles = gladaTask.architecture?.target_files || [];
  const taskModules = gladaTask.architecture?.target_modules || [];
  const taskTags = extractTags(gladaTask.plan.title, []);

  const scored = allSkills.map(skill => {
    let score = 0;
    const skillData = skill.skill;

    // 1. 文件域重叠
    const skillFiles = skillData.file_domain || [];
    const fileOverlap = taskFiles.filter(f =>
      skillFiles.some(sf => sf === f || sf.startsWith(path.dirname(f) + '/'))
    ).length;
    score += fileOverlap * 3;

    // 2. 标签匹配
    const skillTags = skillData.tags || [];
    const tagOverlap = taskTags.filter(t => skillTags.includes(t)).length;
    score += tagOverlap * 2;

    // 3. 模块匹配
    const skillModules = skillData.architecture_context?.target_modules || [];
    const moduleOverlap = taskModules.filter(m => skillModules.includes(m)).length;
    score += moduleOverlap * 2;

    // 4. 成功率加权
    score *= (skillData.success_rate || 0.5);

    return { skill, score };
  });

  return scored
    .filter(s => s.score > 0)
    .sort((a, b) => b.score - a.score)
    .slice(0, maxResults)
    .map(s => s.skill);
}

/**
 * 将 skills 格式化为 LLM 可读的上下文片段
 *
 * @param {Object[]} skills - skill 文档列表
 * @returns {string} 格式化的上下文文本
 */
function skillsToContext(skills) {
  if (!skills || skills.length === 0) {
    return '';
  }

  const parts = ['--- 已有的经验 Skill（从之前成功的任务中蒸馏） ---'];

  for (const skill of skills) {
    const s = skill.skill;
    parts.push(`\n### Skill: ${s.name}`);
    parts.push(`来源: ${s.source_task} | 成功率: ${Math.round((s.success_rate || 0) * 100)}%`);

    if (s.step_patterns && s.step_patterns.length > 0) {
      parts.push('步骤模式:');
      for (const p of s.step_patterns) {
        parts.push(`  - ${p.description}`);
        if (p.reasoning) {
          parts.push(`    原因: ${p.reasoning}`);
        }
        if (p.files_changed && p.files_changed.length > 0) {
          parts.push(`    涉及文件: ${p.files_changed.join(', ')}`);
        }
      }
    }

    if (s.lessons_learned && s.lessons_learned.length > 0) {
      parts.push('⚠️ 教训:');
      for (const lesson of s.lessons_learned) {
        parts.push(`  - ${lesson.step_description}: ${lesson.error}`);
      }
    }

    if (s.file_domain && s.file_domain.length > 0) {
      parts.push(`文件域: ${s.file_domain.join(', ')}`);
    }
  }

  return parts.join('\n');
}

/**
 * 完整的蒸馏流程：从任务中提炼 skill 并保存
 *
 * @param {Object} gladaTask - 已完成的 GLADA 任务
 * @returns {{ skill: Object|null, saved: boolean, path: string|null }}
 */
function distillAndSave(gladaTask) {
  const skill = distillSkill(gladaTask);

  if (!skill) {
    console.log(`[GLADA-Skill] ⏭️ 任务 ${gladaTask.glada_task_id} 不满足蒸馏条件，跳过`);
    return { skill: null, saved: false, path: null };
  }

  const savedPath = saveSkill(skill);
  return { skill, saved: true, path: savedPath };
}

// ── 内部工具函数 ─────────────────────────────────

/**
 * 从任务标题和步骤中提取关键词标签
 * @param {string} title - 任务标题
 * @param {Object[]} patterns - 步骤模式
 * @returns {string[]} 标签列表
 */
function extractTags(title, patterns) {
  const tags = new Set();

  // 从标题提取
  const titleWords = (title || '')
    .toLowerCase()
    .replace(/[^a-z0-9\u4e00-\u9fff\s-]/g, ' ')
    .split(/\s+/)
    .filter(w => w.length > 1);

  for (const word of titleWords) {
    tags.add(word);
  }

  // 从步骤描述提取
  for (const p of patterns) {
    const desc = (p.description || '').toLowerCase();
    // 提取技术关键词
    const techWords = desc.match(/(?:api|route|schema|test|deploy|config|auth|middleware|database|sql|css|html|component|module|service|hook|plugin|skill)/gi);
    if (techWords) {
      techWords.forEach(w => tags.add(w.toLowerCase()));
    }
  }

  // 从文件路径提取模块名
  for (const p of patterns) {
    for (const file of (p.files_changed || [])) {
      const parts = file.split('/');
      if (parts.length > 1) {
        tags.add(parts[0]); // 顶层目录作为标签
      }
    }
  }

  return [...tags].slice(0, 20); // 最多20个标签
}

/**
 * 将字符串转为安全的路径片段
 * @param {string} str - 输入字符串
 * @returns {string} 安全的路径片段（最长60字符，仅含 a-z0-9 中文和连字符）
 */
function sanitizeForPath(str) {
  return (str || 'untitled')
    .toLowerCase()
    .replace(/[^a-z0-9\u4e00-\u9fff-]/g, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .substring(0, 60);
}

module.exports = {
  distillSkill,
  saveSkill,
  loadAllSkills,
  findRelevantSkills,
  skillsToContext,
  distillAndSave,
  extractTags,
  SKILLS_DIR
};
