/**
 * SkillRegistryBuilder — generic skill assembly for OODA agent consumers.
 *
 * Promoted from `forge/src/agents/shared/skill-registry-builder.ts` (sprint-616:quick-3).
 * Replaces 9 quasi-identical `buildXxxSkills()` functions in Forge with a single
 * `buildSkills({ agentId, domain, extras })` factory.
 *
 * Pattern: base skills (universal) + domain extras (least privilege per agent).
 *
 * @public @since 0.18.0
 */
import { z } from "zod";
import { brainStore } from "./brain-store.js";
import { brainQuery } from "./brain-query.js";
import { slackNotify } from "./slack-notify.js";
import { httpFetch } from "./http-fetch.js";
import { BASE_SKILL_NAMES } from "./base-skills.js";
// ─── Zod validation schema ────────────────────────────────────────────────────
// NOTE: `deps` is intentionally excluded from this schema — it contains complex
// runtime objects (BrainPort, LoggerPort) that are not Zod-serializable.
// We validate only the primitive + serializable fields.
const buildSkillsOptionsSchema = z.object({
    agentId: z.string().min(1),
    domain: z.string().min(1),
    extras: z
        .array(z.object({
        name: z.string().min(1),
        skill: z.unknown(),
    }))
        .optional(),
});
// ─── llm-complete factory ─────────────────────────────────────────────────────
/**
 * Build the `llm-complete` skill bound to the provided LiteLLM config.
 * Produces a Skill that calls the LiteLLM `/v1/chat/completions` endpoint.
 *
 * Defined inline rather than a separate file to keep the bound config local.
 */
function buildLlmCompleteSkill(deps) {
    const inputSchema = z
        .object({
        systemPrompt: z.string(),
        userPrompt: z.string(),
        model: z.string().optional(),
        maxTokens: z.number().int().positive().optional(),
    })
        .strict();
    return {
        name: "llm-complete",
        inputSchema,
        async execute(input, ctx) {
            if (ctx.isReplay) {
                const mock = ctx.dryRunMocks["llm-complete"];
                if (mock)
                    return mock(input);
                return { content: "", raw: { replay: true } };
            }
            const litellmUrl = deps.litellmUrl ?? process.env["LITELLM_URL"];
            const apiKey = deps.litellmApiKey ?? process.env["LITELLM_API_KEY"] ?? "sk-sdk";
            if (!litellmUrl) {
                deps.logger.warn?.({ skill: "llm-complete" }, "LITELLM_URL not configured");
                return { content: "", raw: { error: "LITELLM_URL not configured" } };
            }
            try {
                const res = await fetch(`${litellmUrl}/v1/chat/completions`, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json",
                        Authorization: `Bearer ${apiKey}`,
                    },
                    body: JSON.stringify({
                        model: input.model ?? "forge-orient",
                        messages: [
                            { role: "system", content: input.systemPrompt },
                            { role: "user", content: input.userPrompt },
                        ],
                        max_tokens: input.maxTokens ?? 1024,
                        temperature: 0.3,
                    }),
                });
                const data = (await res.json());
                const content = data.choices?.[0]?.message?.content ?? "";
                if (!content) {
                    deps.logger.error?.({ skill: "llm-complete", data }, "empty response content");
                }
                return { content, raw: data };
            }
            catch (err) {
                deps.logger.error?.({ skill: "llm-complete", err }, "fetch failed");
                return { content: "", raw: { error: String(err) } };
            }
        },
    };
}
// ─── Main factory ─────────────────────────────────────────────────────────────
/**
 * Build a SkillRegistry for an agent.
 *
 * Base skills (always included): brain-store, brain-query, slack-notify, llm-complete.
 * Domain extras are merged on top — Zod validation prevents duplicate IDs.
 *
 * @example
 * ```ts
 * const { registry } = buildSkills({
 *   agentId: "forge-revenue",
 *   deps,
 *   domain: "revenue",
 *   extras: [{ name: "http-fetch", skill: httpFetch }],
 * });
 * ```
 *
 * @throws {z.ZodError} if options fail validation
 * @throws {Error} if extras contain a skill ID that collides with a base skill name
 */
export function buildSkills(opts) {
    // Validate serializable fields only (deps excluded — contains non-serializable ports)
    buildSkillsOptionsSchema.parse({
        agentId: opts.agentId,
        domain: opts.domain,
        extras: opts.extras,
    });
    const { deps, extras = [] } = opts;
    // Check for duplicate IDs (extras must not shadow base skills)
    const baseName = new Set(BASE_SKILL_NAMES);
    for (const { name } of extras) {
        if (baseName.has(name)) {
            throw new Error(`buildSkills: extra skill "${name}" collides with a base skill name. ` +
                `Base skills: ${[...baseName].join(", ")}. ` +
                `To override a base skill, use a different name or extend the registry manually.`);
        }
    }
    // Check for duplicate extra names
    const extraNames = extras.map((e) => e.name);
    const uniqueExtras = new Set(extraNames);
    if (uniqueExtras.size !== extraNames.length) {
        const seen = new Set();
        const dupes = [];
        for (const n of extraNames) {
            if (seen.has(n))
                dupes.push(n);
            else
                seen.add(n);
        }
        throw new Error(`buildSkills: duplicate extra skill IDs detected: ${dupes.join(", ")}`);
    }
    // Assemble base registry
    const base = {
        "brain-store": brainStore,
        "brain-query": brainQuery,
        "slack-notify": slackNotify,
        "llm-complete": buildLlmCompleteSkill(deps),
    };
    // Merge extras
    const registry = { ...base };
    for (const { name, skill } of extras) {
        registry[name] = skill;
    }
    return {
        registry,
        baseNames: [...BASE_SKILL_NAMES],
        extraNames,
    };
}
/**
 * Convenience: extract just the SkillRegistry from `buildSkills`.
 * Identical to `buildSkills(opts).registry`.
 */
export function buildSkillRegistry(opts) {
    return buildSkills(opts).registry;
}
// Re-export for convenience
export { httpFetch };
//# sourceMappingURL=skill-registry-builder.js.map