import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import {
  ensurePublishSkillInstalled,
  PUBLISH_SKILL_NAME,
  renderPublishSkill,
  resolvePublicBaseUrl,
} from './user-publish.mjs';

const __dirname = path.dirname(fileURLToPath(import.meta.url));

export const DEFAULT_USER_SKILLS = {
  web: true,
  search: true,
  'schedule-assistant': true,
  'form-builder': true,
  'table-viewer': true,
  'product-campaign-page': true,
  [PUBLISH_SKILL_NAME]: false,
};

/** Optional presets for admin role configuration (creator / developer). */
export const USER_ROLE_SKILL_PRESETS = {
  user: DEFAULT_USER_SKILLS,
  creator: {
    ...DEFAULT_USER_SKILLS,
    [PUBLISH_SKILL_NAME]: true,
    kanban: true,
    timeline: true,
  },
  developer: {
    ...DEFAULT_USER_SKILLS,
    git: true,
    'diff-viewer': true,
    'code-playground': true,
    'test-runner': true,
  },
};

export function parseSkillFrontmatter(content) {
  const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
  if (!match) return { name: null, description: '' };
  const block = match[1];
  const name = block.match(/^name:\s*(.+)$/m)?.[1]?.trim() ?? null;
  const description = block.match(/^description:\s*(.+)$/m)?.[1]?.trim() ?? '';
  return { name, description };
}

export function listPlatformSkillCatalog(h5Root = __dirname) {
  const skillsRoot = path.join(h5Root, 'skills');
  if (!fs.existsSync(skillsRoot)) return [];

  const catalog = [];
  for (const entry of fs.readdirSync(skillsRoot, { withFileTypes: true })) {
    if (!entry.isDirectory()) continue;
    const skillPath = path.join(skillsRoot, entry.name, 'SKILL.md');
    if (!fs.existsSync(skillPath)) continue;
    const raw = fs.readFileSync(skillPath, 'utf8');
    const meta = parseSkillFrontmatter(raw);
    const name = meta.name || entry.name;
    catalog.push({
      name,
      dirName: entry.name,
      label: name,
      description: meta.description || '平台通用技能',
      category: 'platform',
      requiresPublish: name === PUBLISH_SKILL_NAME,
    });
  }
  return catalog.sort((a, b) => a.name.localeCompare(b.name));
}

export function catalogSkillNames(catalog) {
  return catalog.map((item) => item.name);
}

export function isValidSkillName(catalog, name) {
  return catalog.some((item) => item.name === name);
}

export function normalizeSkillPatch(catalog, patch) {
  const normalized = {};
  for (const [key, value] of Object.entries(patch ?? {})) {
    if (!isValidSkillName(catalog, key)) continue;
    normalized[key] = Boolean(value);
  }
  return normalized;
}

export function resolveSkillMap(roleGrants, userOverrides, catalog) {
  const resolved = {};
  for (const item of catalog) {
    const key = item.name;
    if (key in userOverrides) {
      resolved[key] = userOverrides[key];
    } else if (key in roleGrants) {
      resolved[key] = roleGrants[key];
    } else {
      resolved[key] = DEFAULT_USER_SKILLS[key] ?? false;
    }
  }
  return resolved;
}

export function grantedSkillNames(skillMap) {
  return Object.entries(skillMap)
    .filter(([, enabled]) => enabled)
    .map(([name]) => name);
}

export function applySkillGrantsToCapabilities(capabilities, skillMap) {
  const effective = { ...capabilities };
  const enabled = grantedSkillNames(skillMap);
  if (enabled.length > 0) {
    effective.skills = true;
  }
  if (enabled.includes(PUBLISH_SKILL_NAME)) {
    effective.static_publish = true;
  }
  return effective;
}

function copySkillTree(srcDir, destDir) {
  fs.mkdirSync(destDir, { recursive: true });
  for (const entry of fs.readdirSync(srcDir, { withFileTypes: true })) {
    const from = path.join(srcDir, entry.name);
    const to = path.join(destDir, entry.name);
    if (entry.isDirectory()) {
      copySkillTree(from, to);
    } else {
      fs.copyFileSync(from, to);
    }
  }
}

export function syncSkillsToWorkspace({
  h5Root,
  publishDir,
  skillMap,
  catalog,
  user,
  publicBaseUrl,
}) {
  const enabled = new Set(grantedSkillNames(skillMap));
  const platformNames = new Set(catalog.map((item) => item.name));
  const agentsSkills = path.join(publishDir, '.agents', 'skills');

  if (fs.existsSync(agentsSkills)) {
    for (const entry of fs.readdirSync(agentsSkills, { withFileTypes: true })) {
      if (!entry.isDirectory()) continue;
      const skillName = entry.name;
      const catalogItem = catalog.find((item) => item.name === skillName || item.dirName === skillName);
      const resolvedName = catalogItem?.name ?? skillName;
      if (platformNames.has(resolvedName) && !enabled.has(resolvedName)) {
        fs.rmSync(path.join(agentsSkills, entry.name), { recursive: true, force: true });
      }
    }
  }

  for (const item of catalog) {
    if (!enabled.has(item.name)) continue;
    const srcDir = path.join(h5Root, 'skills', item.dirName);
    const destDir = path.join(agentsSkills, item.name);
    if (item.name === PUBLISH_SKILL_NAME && user) {
      ensurePublishSkillInstalled(publishDir, {
        slug: String(user.id).trim().toLowerCase(),
        username: user.username ? String(user.username).trim().toLowerCase() : undefined,
        publicBaseUrl,
        publishDir,
      });
      continue;
    }
    if (fs.existsSync(srcDir)) {
      if (fs.existsSync(destDir)) fs.rmSync(destDir, { recursive: true, force: true });
      copySkillTree(srcDir, destDir);
    }
  }
}
