/**
 * Skill snapshot for the DeepSeek-via-Hermes adapter.
 *
 * Hermes manages its own skills under ~/.hermes/skills/ (global; not per-profile).
 * Paperclip-managed skills declared in adapter config are surfaced as
 * "company_managed" entries — same behavior as the upstream Hermes adapter.
 */

import fs from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import {
  readPaperclipRuntimeSkillEntries,
  resolvePaperclipDesiredSkillNames,
} from "@paperclipai/adapter-utils/server-utils";
import { ADAPTER_TYPE } from "../shared/constants.js";

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

function asString(value) {
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
}

function parseSkillFrontmatter(content) {
  const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
  if (!match) return {};
  const fm = {};
  for (const line of match[1].split("\n")) {
    const idx = line.indexOf(":");
    if (idx === -1) continue;
    const key = line.slice(0, idx).trim();
    let val = line.slice(idx + 1).trim();
    if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
      val = val.slice(1, -1);
    }
    fm[key] = val;
  }
  return fm;
}

async function buildSkillEntry(key, skillMdPath, categoryPath) {
  let description = null;
  try {
    const content = await fs.readFile(skillMdPath, "utf8");
    description = parseSkillFrontmatter(content).description ?? null;
  } catch {
    // ignore
  }
  return {
    key,
    runtimeName: key,
    desired: true,
    managed: false,
    state: "installed",
    origin: "user_installed",
    originLabel: "Hermes skill",
    locationLabel: `~/.hermes/skills/${categoryPath}`,
    readOnly: true,
    sourcePath: skillMdPath,
    targetPath: null,
    detail: description,
  };
}

async function scanHermesSkills(skillsHome) {
  const entries = [];
  try {
    const cats = await fs.readdir(skillsHome, { withFileTypes: true });
    for (const cat of cats) {
      if (!cat.isDirectory()) continue;
      const catPath = path.join(skillsHome, cat.name);
      const topSkill = path.join(catPath, "SKILL.md");
      if (await fs.stat(topSkill).catch(() => null)) {
        entries.push(await buildSkillEntry(cat.name, topSkill, cat.name));
      }
      const items = await fs.readdir(catPath, { withFileTypes: true }).catch(() => []);
      for (const item of items) {
        if (!item.isDirectory()) continue;
        const skillMd = path.join(catPath, item.name, "SKILL.md");
        if (await fs.stat(skillMd).catch(() => null)) {
          entries.push(await buildSkillEntry(item.name, skillMd, `${cat.name}/${item.name}`));
        }
      }
    }
  } catch {
    // ~/.hermes/skills/ doesn't exist
  }
  return entries.sort((a, b) => a.key.localeCompare(b.key));
}

async function buildSnapshot(config) {
  const homedir =
    asString(config.env?.HOME) ??
    process.env.HOME ??
    "/home/chaim";
  const hermesSkillsHome = path.join(homedir, ".hermes", "skills");

  const paperclipEntries = await readPaperclipRuntimeSkillEntries(config, __moduleDir);
  const desiredSkills = resolvePaperclipDesiredSkillNames(config, paperclipEntries);
  const desiredSet = new Set(desiredSkills);
  const availableByKey = new Map(paperclipEntries.map((e) => [e.key, e]));

  const hermesSkillEntries = await scanHermesSkills(hermesSkillsHome);
  const hermesKeys = new Set(hermesSkillEntries.map((e) => e.key));

  const entries = [];
  const warnings = [];

  for (const entry of paperclipEntries) {
    const desired = desiredSet.has(entry.key);
    entries.push({
      key: entry.key,
      runtimeName: entry.runtimeName,
      desired,
      managed: true,
      state: desired ? "configured" : "available",
      origin: entry.required ? "paperclip_required" : "company_managed",
      originLabel: entry.required ? "Required by Paperclip" : "Managed by Paperclip",
      readOnly: false,
      sourcePath: entry.source,
      targetPath: null,
      detail: desired ? "Will be available on the next run via Hermes skill loading." : null,
      required: Boolean(entry.required),
      requiredReason: entry.requiredReason ?? null,
    });
  }

  for (const entry of hermesSkillEntries) {
    if (availableByKey.has(entry.key)) continue;
    entries.push(entry);
  }

  for (const desired of desiredSkills) {
    if (availableByKey.has(desired) || hermesKeys.has(desired)) continue;
    warnings.push(`Desired skill "${desired}" is not available in Paperclip or Hermes skills.`);
    entries.push({
      key: desired,
      runtimeName: null,
      desired: true,
      managed: true,
      state: "missing",
      origin: "external_unknown",
      originLabel: "External or unavailable",
      readOnly: false,
      sourcePath: null,
      targetPath: null,
      detail: "Cannot find this skill in Paperclip or ~/.hermes/skills/.",
    });
  }

  return {
    adapterType: ADAPTER_TYPE,
    supported: true,
    mode: "persistent",
    desiredSkills,
    entries,
    warnings,
  };
}

export async function listSkills(ctx) {
  return buildSnapshot(ctx.config);
}

export async function syncSkills(ctx, _desired) {
  return buildSnapshot(ctx.config);
}

export function resolveDesiredSkillNames(config, availableEntries) {
  return resolvePaperclipDesiredSkillNames(config, availableEntries);
}
