import * as z from "zod/v4";
import { jsonResult, errorResult } from "../utils/response-formatter.js";
import { createLogger } from "../utils/logger.js";
import { SCHEMAS } from "../data/schemas/index.js";
import { getExample, searchExamples, getExamplesForResource } from "../data/examples/index.js";
import { schemaOutputSchema } from "./output-schemas.js";
const log = createLogger("tool:harness-schema");
/**
 * Resolve a $ref pointer within the schema.
 * E.g. "#/definitions/trigger/trigger_source" → schema.definitions.trigger.trigger_source
 */
function resolveRef(schema, ref) {
    if (!ref.startsWith("#/"))
        return undefined;
    const parts = ref.slice(2).split("/");
    let current = schema;
    for (const part of parts) {
        if (current && typeof current === "object" && !Array.isArray(current)) {
            current = current[part];
        }
        else {
            return undefined;
        }
    }
    return current;
}
/**
 * Inline $ref references one level deep so the returned schema fragment
 * is self-contained and useful without chasing references.
 */
function inlineRefs(schema, node, depth = 0) {
    if (depth > 3)
        return node; // prevent infinite recursion
    if (!node || typeof node !== "object")
        return node;
    if (Array.isArray(node)) {
        return node.map((item) => inlineRefs(schema, item, depth));
    }
    const obj = node;
    // If this node is a $ref, resolve it
    if (typeof obj["$ref"] === "string") {
        const resolved = resolveRef(schema, obj["$ref"]);
        if (resolved && typeof resolved === "object") {
            return inlineRefs(schema, resolved, depth + 1);
        }
        return obj;
    }
    // Recurse into child properties
    const result = {};
    for (const [key, value] of Object.entries(obj)) {
        if (key === "$schema")
            continue; // strip noise
        result[key] = inlineRefs(schema, value, depth + 1);
    }
    return result;
}
/**
 * Navigate into definitions by dot-separated path.
 * E.g. "trigger_source" → definitions.trigger.trigger_source
 *       "scheduled_trigger" → definitions.trigger.scheduled_trigger
 */
function navigateToPath(schema, resourceType, path) {
    const definitions = schema.definitions;
    if (!definitions)
        return undefined;
    const resourceDefs = definitions[resourceType];
    if (!resourceDefs)
        return undefined;
    // Try direct key first
    if (resourceDefs[path])
        return resourceDefs[path];
    // Try dot-separated path
    const parts = path.split(".");
    let current = resourceDefs;
    for (const part of parts) {
        if (current && typeof current === "object" && !Array.isArray(current)) {
            current = current[part];
        }
        else {
            return undefined;
        }
    }
    return current;
}
/**
 * Get a compact summary of the top-level structure: property names, types,
 * required fields, and available definition sections.
 */
function getSummary(schema, resourceType) {
    const definitions = schema.definitions;
    // Harness-generated schemas nest the root definition under definitions[type][type].
    // Plain JSON Schemas (extension schemas) place properties at the root level.
    const harnessRootDef = definitions?.[resourceType]?.[resourceType];
    const rootDef = harnessRootDef ?? (schema.properties ? schema : undefined);
    const sections = definitions ? Object.keys(definitions[resourceType] ?? {}) : [];
    const properties = rootDef?.properties;
    const required = rootDef?.required;
    const fields = [];
    if (properties) {
        for (const [name, spec] of Object.entries(properties)) {
            const s = spec;
            fields.push({
                name,
                type: s.type ?? (s["$ref"] ? "object ($ref)" : "unknown"),
                required: required?.includes(name) ?? false,
                ...(s["$ref"] ? { ref: s["$ref"].split("/").pop() } : {}),
            });
        }
    }
    return {
        resource_type: resourceType,
        fields,
        available_sections: sections,
        hint: "Use path parameter to drill into a section. E.g. path='trigger_source' for source structure, path='scheduled_trigger' for cron spec.",
    };
}
export function registerSchemaTool(server, additionalSchemas) {
    if (additionalSchemas) {
        for (const key of Object.keys(additionalSchemas)) {
            if (key in SCHEMAS) {
                throw new Error(`additionalSchemas key '${key}' conflicts with a built-in schema name`);
            }
        }
    }
    const allSchemas = additionalSchemas
        ? { ...SCHEMAS, ...Object.fromEntries(Object.entries(additionalSchemas).map(([k, v]) => [k, v.schema])) }
        : { ...SCHEMAS };
    const availableSchemas = Object.keys(allSchemas);
    server.registerTool("harness_schema", {
        description: "Fetch Harness YAML schema or examples for a resource type. " +
            "Use without path for a summary of fields and available sections. " +
            "Use with path to drill into a specific section. " +
            "Use with example to fetch a named example YAML snippet. " +
            "Use with example_search to find examples by keyword. " +
            "Precedence: example > example_search > path > summary. " +
            `Available schemas: ${availableSchemas.join(", ")}.`,
        inputSchema: {
            resource_type: z
                .enum(availableSchemas)
                .describe(`Schema to fetch. Available: ${availableSchemas.join(", ")}. Required for schema/path lookups, optional for example_search.`)
                .optional(),
            path: z
                .string()
                .optional()
                .describe("Dot-separated path to drill into a specific definition section. " +
                "Omit for a top-level summary showing all available sections."),
            example: z
                .string()
                .optional()
                .describe("Fetch a specific example by name (e.g. 'minimal-ci'). Returns the full YAML snippet and description."),
            example_search: z
                .string()
                .optional()
                .describe("Search examples by keyword. Returns matching example names and descriptions. Optionally combine with resource_type to filter."),
        },
        outputSchema: schemaOutputSchema,
        annotations: {
            title: "Harness YAML Schema",
            readOnlyHint: true,
            destructiveHint: false,
            // Bundled schemas/examples only — no external API call
            openWorldHint: false,
        },
    }, async (args) => {
        try {
            // --- Example fetch mode ---
            if (args.example) {
                const ex = getExample(args.example);
                if (!ex) {
                    const available = args.resource_type
                        ? getExamplesForResource(args.resource_type).map((e) => e.name)
                        : [];
                    return jsonResult({
                        error: `Example '${args.example}' not found.` +
                            (available.length ? ` Available for ${args.resource_type}: ${available.join(", ")}` : " Use example_search to find examples."),
                        available_examples: available,
                    });
                }
                return jsonResult({
                    name: ex.name,
                    resourceType: ex.resourceType,
                    description: ex.description,
                    tags: ex.tags,
                    yaml: ex.yaml,
                });
            }
            // --- Example search mode ---
            if (args.example_search) {
                const results = searchExamples(args.example_search, args.resource_type);
                return jsonResult({
                    search: args.example_search,
                    ...(args.resource_type ? { resource_type: args.resource_type } : {}),
                    total: results.length,
                    results: results.map((e) => ({
                        name: e.name,
                        resourceType: e.resourceType,
                        description: e.description,
                        tags: e.tags,
                    })),
                    hint: results.length > 0
                        ? "Use example='<name>' to fetch the full YAML for any result."
                        : "No matches. Try a broader keyword or omit resource_type to search globally.",
                });
            }
            // --- Schema mode (existing behavior) ---
            if (!args.resource_type) {
                return errorResult("resource_type is required for schema lookups. Use example_search to search examples without specifying a resource type.");
            }
            const schema = allSchemas[args.resource_type];
            // No path → return summary with available examples
            if (!args.path) {
                const summary = getSummary(schema, args.resource_type);
                const examples = getExamplesForResource(args.resource_type);
                if (examples.length > 0) {
                    summary.examples_available = examples.map((e) => e.name);
                }
                return jsonResult(summary);
            }
            // Navigate to the requested path
            const node = navigateToPath(schema, args.resource_type, args.path);
            if (!node) {
                const definitions = schema.definitions;
                const available = definitions ? Object.keys(definitions[args.resource_type] ?? {}) : [];
                return errorResult(`Path '${args.path}' not found in ${args.resource_type} schema. ` +
                    `Available sections: ${available.join(", ")}`);
            }
            // Inline $ref references so the result is self-contained
            const resolved = inlineRefs(schema, node);
            return jsonResult({
                resource_type: args.resource_type,
                path: args.path,
                schema: resolved,
            });
        }
        catch (err) {
            return errorResult(err instanceof Error ? err.message : String(err));
        }
    });
}
//# sourceMappingURL=harness-schema.js.map