/**
 * Skill YAML frontmatter parser
 *
 * Purpose: parse SKILL.md frontmatter so SF can enforce invocation policy,
 * permission profiles, and side-effect awareness without loading full skill
 * content into model context.
 *
 * Consumer: skill loader, auto-skill creation, and permission gating.
 */
import { splitFrontmatter } from "../../shared/frontmatter.js";

/**
 * Parse YAML frontmatter from skill markdown content.
 *
 * Returns { frontmatter: object, body: string } or null if no frontmatter.
 */
export function parseSkillFrontmatter(content) {
	if (!content) return null;
	const [fmLines, body] = splitFrontmatter(content);
	if (!fmLines) return null;
	const frontmatter = parseYaml(fmLines.join("\n"));
	return { frontmatter, body };
}

/**
 * Minimal YAML parser for skill frontmatter.
 *
 * Supports: strings, booleans, numbers, arrays, and simple nested objects.
 * Does NOT support anchors, aliases, or complex YAML features.
 */
function parseYaml(text) {
	const result = {};
	const lines = text.split("\n");
	let currentKey = null;
	let currentArray = null;

	for (const rawLine of lines) {
		const line = rawLine.trimEnd();
		if (!line.trim() || line.trim().startsWith("#")) continue;

		// Check for key: value
		const keyMatch = line.match(/^(\w[\w-]*):\s*(.*)$/);
		if (keyMatch) {
			const [, key, value] = keyMatch;
			currentKey = key;

			if (value.trim() === "") {
				// Could be object or array start
				currentArray = null;
				continue;
			}

			result[key] = parseYamlValue(value.trim());
			currentArray = null;
			continue;
		}

		// Array item: - value (may be indented)
		const arrayMatch = line.match(/^\s+-\s+(.*)$/);
		if (arrayMatch && currentKey) {
			if (!currentArray) {
				currentArray = [];
				result[currentKey] = currentArray;
			}
			currentArray.push(parseYamlValue(arrayMatch[1].trim()));
		}
	}

	return result;
}

function parseYamlValue(value) {
	if (value === "true" || value === "yes") return true;
	if (value === "false" || value === "no") return false;
	if (value === "null" || value === "~") return null;

	// Number
	if (/^-?\d+$/.test(value)) return Number.parseInt(value, 10);
	if (/^-?\d+\.\d+$/.test(value)) return Number.parseFloat(value);

	// Quoted string
	if (
		(value.startsWith('"') && value.endsWith('"')) ||
		(value.startsWith("'") && value.endsWith("'"))
	) {
		return value.slice(1, -1);
	}

	return value;
}

/**
 * Validate skill frontmatter against required fields.
 *
 * Project and user skills follow the open Agent Skills ecosystem standard:
 * only `name` and `description` are required. SF-specific fields
 * (user-invocable, model-invocable, side-effects, permission-profile) are
 * optional — defaults are applied in buildSkillRecord.
 */
export function validateSkillFrontmatter(frontmatter) {
	const errors = [];
	if (!frontmatter.name || typeof frontmatter.name !== "string") {
		errors.push("Missing or invalid 'name' field");
	}
	if (!frontmatter.description || typeof frontmatter.description !== "string") {
		errors.push("Missing or invalid 'description' field");
	}

	const validProfiles = ["restricted", "normal", "trusted", "unrestricted"];
	if (
		frontmatter["permission-profile"] &&
		!validProfiles.includes(frontmatter["permission-profile"])
	) {
		errors.push(
			`Invalid permission-profile: ${frontmatter["permission-profile"]}. Must be one of: ${validProfiles.join(", ")}`,
		);
	}

	return {
		valid: errors.length === 0,
		errors,
	};
}

/**
 * Build a canonical skill record from parsed frontmatter + body.
 *
 * Purpose: produce a typed, normalized skill record so callers never
 * access raw frontmatter keys directly.
 *
 * SF-specific fields default to safe values when absent, preserving
 * compatibility with the open Agent Skills ecosystem standard which
 * only mandates name + description.
 *
 * Consumer: skill loader, /skills catalog, model context assembly.
 */
export function buildSkillRecord(skillDir, frontmatter, body) {
	return {
		name: frontmatter.name,
		description: frontmatter.description,
		userInvocable: frontmatter["user-invocable"] ?? true,
		modelInvocable: frontmatter["model-invocable"] ?? true,
		sideEffects: frontmatter["side-effects"] ?? "none",
		permissionProfile: frontmatter["permission-profile"] ?? "normal",
		triggers: frontmatter.triggers ?? [],
		maxActivations: frontmatter["max-activations"] ?? null,
		locked: frontmatter.locked === true,
		body,
		path: skillDir,
	};
}
