/**
 * SkillManager 技能管理器
 * 加载和管理 Skill
 */

const fs = require('fs');
const path = require('path');
const { Plugin } = require('../core/plugin-base');
const { logger } = require('../utils/logger');
const log = logger.child('SkillManager');
const { z } = require('zod');

/**
 * 验证 skill 名称
 * 1-64字符，字母数字、下划线和连字符，不能以连字符或下划线开头或结尾
 */
function isValidSkillName(name) {
  if (!name || name.length < 1 || name.length > 64) return false;
  if (!/^[a-zA-Z0-9_-]+$/.test(name)) return false;
  if (name.startsWith('-') || name.startsWith('_') || name.endsWith('-') || name.endsWith('_'))
    return false;
  if (/--/.test(name) || /__/.test(name)) return false;
  return true;
}

/**
 * 解析 YAML frontmatter
 */
function parseFrontmatter(content) {
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
  if (!match) return null;

  const frontmatter = {};
  const lines = match[1].split('\n');
  let currentKey = null;

  for (const line of lines) {
    // 处理 metadata 嵌套
    if (currentKey === 'metadata') {
      if (line.match(/^ {2}[a-zA-Z]/)) {
        const colonIndex = line.indexOf(':');
        if (colonIndex > 0) {
          const key = line.substring(2, colonIndex).trim();
          const value = line
            .substring(colonIndex + 1)
            .trim()
            .replace(/^["']|["']$/g, '');
          frontmatter[currentKey][key] = value;
          continue;
        }
      } else if (line.match(/^[a-zA-Z]/)) {
        currentKey = null;
        continue;
      }
    }

    const colonIndex = line.indexOf(':');
    if (colonIndex === -1) continue;

    const key = line.substring(0, colonIndex).trim();
    let value = line.substring(colonIndex + 1).trim();

    // 移除引号
    if (
      (value.startsWith('"') && value.endsWith('"')) ||
      (value.startsWith("'") && value.endsWith("'"))
    ) {
      value = value.slice(1, -1);
    }

    if (key === 'metadata') {
      currentKey = 'metadata';
      frontmatter.metadata = {};
    } else if (key === 'allowed-tools') {
      frontmatter[key] = value
        .split(',')
        .map((t) => t.trim().replace(/^["']|["']$/g, ''))
        .filter((t) => t);
    } else {
      frontmatter[key] = value;
    }
  }

  return frontmatter;
}

/**
 * 移除 frontmatter，获取正文
 */
function stripFrontmatter(content) {
  const match = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/);
  return match ? content.slice(match[0].length).trim() : content.trim();
}

/**
 * Skill 元数据
 */
class SkillMetadata {
  constructor(data) {
    this.name = data.name || '';
    this.description = data.description || '';
    this.license = data.license || null;
    this.compatibility = data.compatibility || null;
    this.metadata = data.metadata || {};
    this.allowedTools = data.allowedTools || [];
  }
}

/**
 * Skill 类
 */
class Skill {
  constructor(metadata, content) {
    this.metadata = metadata;
    this.content = content;
    this._framework = null;
  }

  /**
   * 安装 skill
   */
  install(framework) {
    this._framework = framework;
    return this;
  }

  /**
   * 获取工具定义
   */
  getTools() {
    return [];
  }
}

/**
 * SkillManager 插件
 */
class SkillManagerPlugin extends Plugin {
  constructor(config = {}) {
    super();
    this.name = 'skill-manager';
    this.version = '1.0.0';
    this.description = '技能管理器，加载和管理 Skill';
    this.priority = 5;
    this.system = true;

    this._framework = null;
    this._skillsDirs = Array.isArray(config.skillsDirs)
      ? config.skillsDirs
      : [config.skillsDir || '.agent/skills', 'skills'];
    this._skills = new Map();
    this._loaded = false;
  }

  install(framework) {
    this._framework = framework;
    return this;
  }

  start(framework) {
    this._loadAllSkills();

    // 注册 loadSkill 工具
    framework.registerTool({
      name: 'loadSkill',
      description: '加载指定技能，获取技能的使用指南和内容',
      inputSchema: z.object({
        skill: z.string().describe('技能名称'),
      }),
      execute: async (args) => {
        const skillName = args.skill;
        const skill = this.getSkill(skillName);
        if (!skill) {
          return { success: false, error: `Skill '${skillName}' not found` };
        }
        return {
          success: true,
          name: skill.name,
          description: skill.metadata?.description || '',
          content: skill.content,
        };
      },
    });

    // 注册 reloadSkills 工具
    framework.registerTool({
      name: 'reloadSkills',
      description: '重载所有技能，当用户添加新技能或修改技能后调用此工具',
      inputSchema: z.object({}),
      execute: async () => {
        this.reload(this._framework);
        return {
          success: true,
          message: `Skills reloaded. Total: ${this._skills.size}`,
          skills: Array.from(this._skills.keys()),
        };
      },
    });

    // 注册 loadReference 工具（按需加载 skill 的附加文档）
    framework.registerTool({
      name: 'loadReference',
      description: '加载指定技能的附加参考文档（references 目录下的文件）',
      inputSchema: z.object({
        skill: z.string().describe('技能名称'),
        reference: z.string().describe('参考文档名称（不含 .md 后缀）'),
        list: z.boolean().optional().describe('如果为 true，列出该技能的所有可用的 reference 文件'),
      }),
      execute: async (args) => {
        if (args.list) {
          // 列出该技能的所有 reference
          const refs = this.listReferences(args.skill);
          return {
            success: true,
            skill: args.skill,
            references: refs,
          };
        }

        const content = this.loadReference(args.skill, args.reference);
        if (content === null) {
          return {
            success: false,
            error: `Reference '${args.reference}' not found in skill '${args.skill}'`,
          };
        }
        return {
          success: true,
          skill: args.skill,
          reference: args.reference,
          content,
        };
      },
    });

    // 注册 listScripts 工具（列出 skill 的脚本）
    framework.registerTool({
      name: 'listScripts',
      description: '列出指定技能下的所有可执行脚本',
      inputSchema: z.object({
        skill: z.string().describe('技能名称'),
      }),
      execute: async (args) => {
        const scripts = this.listScripts(args.skill);
        return {
          success: true,
          skill: args.skill,
          scripts,
        };
      },
    });

    // 注册 loadScript 工具（读取脚本内容）
    framework.registerTool({
      name: 'loadScript',
      description: '读取指定技能下脚本文件的内容',
      inputSchema: z.object({
        skill: z.string().describe('技能名称'),
        script: z.string().describe('脚本名称（包含扩展名）'),
      }),
      execute: async (args) => {
        const content = this.loadScript(args.skill, args.script);
        if (content === null) {
          return {
            success: false,
            error: `Script '${args.script}' not found in skill '${args.skill}'`,
          };
        }
        return {
          success: true,
          skill: args.skill,
          script: args.script,
          content,
        };
      },
    });

    return this;
  }

  /**
   * 加载所有 skills
   */
  _loadAllSkills() {
    if (this._loaded) return;

    let totalLoaded = 0;

    // 1. 扫描 skillsDirs
    for (const skillsDir of this._skillsDirs) {
      const resolvedDir = path.resolve(process.cwd(), skillsDir);

      if (!fs.existsSync(resolvedDir)) {
        continue;
      }

      try {
        const entries = fs.readdirSync(resolvedDir, { withFileTypes: true });

        for (const entry of entries) {
          if (!entry.isDirectory()) continue;

          const skillPath = path.join(resolvedDir, entry.name);

          if (!isValidSkillName(entry.name)) {
            continue;
          }

          // 跳过已加载的 skill
          if (this._skills.has(entry.name)) {
            continue;
          }

          try {
            this._loadSkill(entry.name, skillPath);
            totalLoaded++;
          } catch (err) {
            log.error(` Failed to load skill '${entry.name}':`, err.message);
          }
        }
      } catch (err) {
        log.error('Failed to load skills from:', skillsDir, err.message);
      }
    }

    // 2. 扫描插件目录下的 SKILL.md
    this._loadSkillsFromPlugins();

    log.info(` Loaded ${this._skills.size} skills`);
    this._loaded = true;
  }

  /**
   * 从已加载插件的目录中扫描 SKILL.md 并加载为技能
   */
  _loadSkillsFromPlugins() {
    if (!this._framework) return;

    try {
      // 获取所有已注册插件的 sourcePath
      const pluginManager = this._framework.pluginManager;
      const plugins = pluginManager._plugins || new Map();

      for (const [pluginName, entry] of plugins) {
        const sourcePath = entry.sourcePath;
        if (!sourcePath) continue;

        // 获取插件所在目录
        const pluginDir = path.dirname(sourcePath);

        // 检查插件目录下是否有 SKILL.md（尝试大小写）
        let skillMdPath = path.join(pluginDir, 'SKILL.md');
        if (!fs.existsSync(skillMdPath)) {
          skillMdPath = path.join(pluginDir, 'SKILL.MD');
        }
        if (!fs.existsSync(skillMdPath)) {
          // 使用 _findSkillMarkdown 递归查找
          const found = this._findSkillMarkdown(pluginDir);
          if (found) {
            skillMdPath = found;
          } else {
            continue;
          }
        }

        // 使用插件名作为 skill 名（如果已存在则跳过）
        const skillName = pluginName;
        if (this._skills.has(skillName)) {
          continue;
        }

        try {
          this._loadSkillFromFile(skillName, skillMdPath, pluginDir);
          log.info(` Loaded skill from plugin '${pluginName}': ${skillName}`);
        } catch (err) {
          log.warn(` Failed to load skill from plugin '${pluginName}':`, err.message);
        }
      }
    } catch (err) {
      log.warn('Failed to scan plugins for skills:', err.message);
    }
  }

  /**
   * 从文件加载技能（用于插件目录的 SKILL.md）
   * @param {string} name - 技能名称
   * @param {string} filePath - SKILL.md 文件路径
   * @param {string} baseDir - 技能基础目录
   */
  _loadSkillFromFile(name, filePath, baseDir) {
    const content = fs.readFileSync(filePath, 'utf-8');
    const frontmatter = parseFrontmatter(content);

    if (!frontmatter) {
      throw new Error('No valid frontmatter found');
    }

    const metadata = new SkillMetadata({
      name: frontmatter.name || name,
      description: frontmatter.description || '',
      license: frontmatter.license,
      compatibility: frontmatter.compatibility,
      metadata: frontmatter.metadata || {},
      allowedTools: frontmatter['allowed-tools'] || [],
    });

    const skill = new Skill(metadata, stripFrontmatter(content));
    skill.install(this._framework);

    // 扫描 references 子目录
    const references = this._scanReferences(baseDir);

    // 扫描 scripts 子目录
    const scripts = this._scanScripts(baseDir);

    this._skills.set(name, {
      name,
      metadata,
      content: skill.content,
      instance: skill,
      path: baseDir,
      references,
      scripts,
      fromPlugin: true, // 标记为来自插件
    });
  }

  /**
   * 递归查找 SKILL.md 或 AGENTS.md（支持多层嵌套目录）
   * @param {string} dir - 要搜索的目录
   * @returns {string|null} 找到的 markdown 文件路径
   */
  _findSkillMarkdown(dir) {
    if (!fs.existsSync(dir) || !fs.statSync(dir).isDirectory()) {
      return null;
    }

    const entries = fs.readdirSync(dir, { withFileTypes: true });

    // 第一遍：优先查找 SKILL.MD
    for (const entry of entries) {
      if (entry.isFile() && entry.name.toUpperCase() === 'SKILL.MD') {
        return path.join(dir, entry.name);
      }
    }

    // 第二遍：查找 AGENTS.MD
    for (const entry of entries) {
      if (entry.isFile() && entry.name.toUpperCase() === 'AGENTS.MD') {
        return path.join(dir, entry.name);
      }
    }

    // 如果没找到，递归搜索子目录（排除 node_modules）
    for (const entry of entries) {
      if (entry.isDirectory() && entry.name !== 'node_modules') {
        const subPath = path.join(dir, entry.name);
        const found = this._findSkillMarkdown(subPath);
        if (found) return found;
      }
    }

    return null;
  }

  /**
   * 加载单个 skill
   */
  _loadSkill(name, skillPath) {
    // 查找 markdown 文件，优先加载 SKILL.md 或 AGENTS.md（支持多层嵌套）
    const skillMdPath = this._findSkillMarkdown(skillPath);
    if (!skillMdPath) {
      throw new Error('No markdown file found');
    }

    const mainFile = skillMdPath;
    const content = fs.readFileSync(mainFile, 'utf-8');
    const frontmatter = parseFrontmatter(content);

    if (!frontmatter) {
      throw new Error('No valid frontmatter found');
    }

    const metadata = new SkillMetadata({
      name: frontmatter.name || name,
      description: frontmatter.description || '',
      license: frontmatter.license,
      compatibility: frontmatter.compatibility,
      metadata: frontmatter.metadata || {},
      allowedTools: frontmatter['allowed-tools'] || [],
    });

    const skill = new Skill(metadata, stripFrontmatter(content));
    skill.install(this._framework);

    // 扫描 references 子目录（按需加载的附加文档）
    const references = this._scanReferences(skillPath);

    // 扫描 scripts 子目录（可执行脚本）
    const scripts = this._scanScripts(skillPath);

    this._skills.set(name, {
      name,
      metadata,
      content: skill.content,
      instance: skill,
      path: skillPath,
      references,
      scripts,
    });

    const refsInfo = references.size > 0 ? `, ${references.size} refs` : '';
    const scriptsInfo = scripts.size > 0 ? `, ${scripts.size} scripts` : '';
    //log.info(` Loaded skill: ${name}${refsInfo}${scriptsInfo}`)
  }

  /**
   * 扫描 references 子目录，按需加载
   * @param {string} skillPath - skill 目录路径
   * @returns {Map} references 文件映射 { filename: { path, content } }
   */
  _scanReferences(skillPath) {
    const references = new Map();
    const refsDir = path.join(skillPath, 'references');

    if (!fs.existsSync(refsDir) || !fs.statSync(refsDir).isDirectory()) {
      return references;
    }

    try {
      const entries = fs.readdirSync(refsDir, { withFileTypes: true });
      for (const entry of entries) {
        if (entry.isFile() && entry.name.endsWith('.md')) {
          const refPath = path.join(refsDir, entry.name);
          const refName = entry.name.replace('.md', '');
          references.set(refName, {
            path: refPath,
            content: null, // 延迟加载
          });
        }
      }
    } catch (err) {
      log.warn(` Failed to scan references for ${skillPath}:`, err.message);
    }

    return references;
  }

  /**
   * 扫描 scripts 子目录，获取脚本列表
   * @param {string} skillPath - skill 目录路径
   * @returns {Map} scripts 映射 { filename: { path, isExecutable } }
   */
  _scanScripts(skillPath) {
    const scripts = new Map();
    const scriptsDir = path.join(skillPath, 'scripts');

    if (!fs.existsSync(scriptsDir) || !fs.statSync(scriptsDir).isDirectory()) {
      return scripts;
    }

    try {
      const entries = fs.readdirSync(scriptsDir, { withFileTypes: true });
      for (const entry of entries) {
        if (entry.isFile()) {
          const scriptPath = path.join(scriptsDir, entry.name);
          // 检查文件是否有执行权限（或检查扩展名）
          const isExecutable =
            entry.name.endsWith('.sh') ||
            entry.name.endsWith('.js') ||
            entry.name.endsWith('.py') ||
            entry.name.endsWith('.ts');
          scripts.set(entry.name, {
            path: scriptPath,
            isExecutable,
          });
        }
      }
    } catch (err) {
      log.warn(` Failed to scan scripts for ${skillPath}:`, err.message);
    }

    return scripts;
  }

  /**
   * 按需加载 reference 文件
   * @param {string} skillName - skill 名称
   * @param {string} refName - reference 文件名（不含 .md）
   * @returns {string|null} 文件内容
   */
  loadReference(skillName, refName) {
    const skill = this._skills.get(skillName);
    if (!skill || !skill.references.has(refName)) {
      return null;
    }

    const ref = skill.references.get(refName);
    if (!ref.content) {
      try {
        ref.content = fs.readFileSync(ref.path, 'utf-8');
      } catch (err) {
        log.error(` Failed to load reference ${skillName}/${refName}:`, err.message);
        return null;
      }
    }

    return ref.content;
  }

  /**
   * 获取 skill 的 reference 列表
   * @param {string} skillName
   * @returns {string[]} reference 文件名列表
   */
  listReferences(skillName) {
    const skill = this._skills.get(skillName);
    if (!skill) return [];
    return Array.from(skill.references.keys());
  }

  /**
   * 获取 skill 的 scripts 列表
   * @param {string} skillName
   * @returns {Object[]} script 信息列表 [{ name, path, isExecutable }]
   */
  listScripts(skillName) {
    const skill = this._skills.get(skillName);
    if (!skill) return [];
    return Array.from(skill.scripts.entries()).map(([name, info]) => ({
      name,
      path: info.path,
      isExecutable: info.isExecutable,
    }));
  }

  /**
   * 读取脚本内容
   * @param {string} skillName
   * @param {string} scriptName
   * @returns {string|null}
   */
  loadScript(skillName, scriptName) {
    const skill = this._skills.get(skillName);
    if (!skill || !skill.scripts.has(scriptName)) {
      return null;
    }

    const script = skill.scripts.get(scriptName);
    try {
      return fs.readFileSync(script.path, 'utf-8');
    } catch (err) {
      log.error(` Failed to load script ${skillName}/${scriptName}:`, err.message);
      return null;
    }
  }

  /**
   * 获取所有 skills
   */
  getAllSkills() {
    return Array.from(this._skills.values());
  }

  /**
   * 获取 skill
   */
  getSkill(name) {
    return this._skills.get(name);
  }

  /**
   * 检查 skill 是否存在
   */
  hasSkill(name) {
    return this._skills.has(name);
  }

  /**
   * 获取 skill 数量
   */
  size() {
    return this._skills.size;
  }

  reload(framework) {
    log.info(' Reloading...');
    this._skills.clear();
    this._loaded = false;
    this._framework = framework;
    this._loadAllSkills();
  }

  uninstall(framework) {
    this._skills.clear();
    this._framework = null;
    this._loaded = false;
  }
}

module.exports = {
  SkillManagerPlugin,
  Skill,
  SkillMetadata,
  isValidSkillName,
  parseFrontmatter,
  stripFrontmatter,
};
