import path from "node:path";
import { extractStepsJson, validateSkillSteps, } from "../skill-generator.js";
import { fetchTextResource } from "./web-fetch-executor.js";
// Re-export so existing callers importing from skill-executor keep working.
export { validateSkillSteps };
function parseFrontmatter(content) {
    const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
    if (!fmMatch)
        return {};
    const fields = {};
    for (const line of fmMatch[1].split("\n")) {
        const match = line.match(/^([A-Za-z0-9_-]+):\s*(.*)$/);
        if (match)
            fields[match[1]] = match[2].trim();
    }
    return fields;
}
function safeSkillName(raw) {
    return raw.replace(/[^a-zA-Z0-9_-]/g, "_");
}
function isExplicitBuiltinRef(raw) {
    return raw.trim().toLowerCase().startsWith("builtin:");
}
function sourceNameFromUrl(rawUrl) {
    try {
        const url = new URL(rawUrl);
        const base = path.basename(url.pathname) || "remote-skill";
        return path.basename(base, path.extname(base)) || "remote-skill";
    }
    catch {
        return "remote-skill";
    }
}
export function installSkillMarkdown(skillGenerator, content, opts = {}) {
    const fm = parseFrontmatter(content);
    const baseName = opts.skillName?.trim() ||
        fm.name ||
        opts.sourceName ||
        "skill";
    if (isExplicitBuiltinRef(baseName)) {
        return `Error: built-in skill '${baseName}' is read-only and cannot be overwritten.`;
    }
    const safeBase = safeSkillName(baseName);
    const exists = skillGenerator.workspaceSkillExists(safeBase);
    if (exists && opts.overwrite !== true) {
        return `Skill '${safeBase}' already exists. Pass overwrite=true to replace it (stats preserved) or use a different skillName.`;
    }
    const existingMeta = exists ? skillGenerator.loadSkillMeta(safeBase) : undefined;
    const stepsJson = extractStepsJson(content);
    if (stepsJson) {
        let steps;
        try {
            steps = JSON.parse(stepsJson);
        }
        catch (err) {
            return `Skill steps JSON is invalid: ${err instanceof Error ? err.message : String(err)}`;
        }
        const stepErr = validateSkillSteps(steps);
        if (stepErr)
            return `Invalid skill steps: ${stepErr}`;
        const notesSection = content.split("## Notes")[1];
        const notes = notesSection
            ? notesSection
                .trim()
                .split("\n")
                .filter((l) => l.startsWith("- "))
                .map((l) => l.slice(2))
            : [];
        const description = fm.description || "(installed skill)";
        const result = skillGenerator.saveSkill({
            name: safeBase,
            description,
            steps: steps,
            notes,
        }, existingMeta);
        const verb = exists ? "Replaced" : "Installed";
        return `${verb} skill '${safeBase}' (${steps.length} steps). ${result}`;
    }
    if (Object.keys(fm).length === 0) {
        return "Skill file is missing a dipclaw `## Steps` JSON block and has no frontmatter for instruction-skill installation.";
    }
    const result = skillGenerator.saveInstructionSkill(safeBase, content, existingMeta);
    const verb = exists ? "Replaced" : "Installed";
    return `${verb} instruction skill '${safeBase}'. ${result}`;
}
export async function executeSkillAction(skillGenerator, action, args) {
    switch (action) {
        case "list":
            return skillGenerator.listSkills();
        case "read": {
            const name = args.name;
            if (!name)
                return "Error: 'name' is required for read.";
            const content = skillGenerator.readSkillFile(name);
            return content ?? `Skill not found: ${name}`;
        }
        case "save": {
            const name = args.name;
            if (!name)
                return "Error: 'name' is required for save.";
            const stepsErr = validateSkillSteps(args.steps);
            if (stepsErr)
                return `Error: ${stepsErr}`;
            const description = args.description ?? "";
            const notes = Array.isArray(args.notes)
                ? args.notes
                : undefined;
            // Preserve existing usage/success stats on overwrite
            const existingMeta = skillGenerator.loadSkillMeta(name);
            return skillGenerator.saveSkill({
                name,
                description,
                steps: args.steps,
                notes,
            }, existingMeta);
        }
        case "install": {
            const overrideName = args.skillName ??
                args.name;
            if (typeof args.url === "string" && args.url.trim()) {
                const fetched = await fetchTextResource(args.url, {
                    headers: args.headers,
                    maxBytes: args.maxBytes ?? 256 * 1024,
                    timeoutMs: args.timeoutMs,
                });
                if (!fetched.ok || fetched.text == null) {
                    const status = fetched.status != null
                        ? `HTTP ${fetched.status} ${fetched.statusText ?? ""}: `
                        : "";
                    return `Error: failed to fetch skill URL: ${status}${fetched.error ?? "unknown error"}`;
                }
                return installSkillMarkdown(skillGenerator, fetched.text, {
                    skillName: overrideName,
                    overwrite: args.overwrite === true,
                    sourceName: sourceNameFromUrl(args.url),
                });
            }
            if (typeof args.content === "string" && args.content.trim()) {
                return installSkillMarkdown(skillGenerator, args.content, {
                    skillName: overrideName,
                    overwrite: args.overwrite === true,
                });
            }
            return "Error: install requires either 'url' or 'content'.";
        }
        case "delete": {
            const name = args.name;
            if (!name)
                return "Error: 'name' is required for delete.";
            if (skillGenerator.deleteSkill(name)) {
                return `✓ Skill '${name}' deleted.`;
            }
            if (skillGenerator.isBuiltinSkill(name)) {
                return `Error: built-in skill '${name}' is read-only and cannot be deleted.`;
            }
            return `Skill not found: ${name}`;
        }
        default:
            return `Unknown skill action: ${action}`;
    }
}
export function executeReadOnlySkillAction(skillGenerator, action, args) {
    switch (action) {
        case "list":
            return skillGenerator.listSkills();
        case "read": {
            const name = args.name;
            if (!name)
                return "Error: 'name' is required for read.";
            const content = skillGenerator.readSkillFile(name);
            return content ?? `Skill not found: ${name}`;
        }
        default:
            return (`Error: skill.${action || "(missing action)"} is not allowed during scheduled tasks. ` +
                `Scheduled tasks can only use skill.list and skill.read.`);
    }
}
//# sourceMappingURL=skill-executor.js.map