// hosts/gemini/tool-schema-translator.ts — Zod ↔ Gemini function-call schema translator (SPEC-591)
// Translates Planu's Zod tool input schemas into Gemini's function-calling declaration format
// and translates Gemini tool-call results back to Planu's expected shape.
import { z } from 'zod';
/**
 * Translate a Zod object schema to Gemini function-calling parameter schema.
 * Supports: ZodObject, ZodString, ZodNumber, ZodBoolean, ZodEnum, ZodArray,
 *           ZodOptional, ZodNullable.
 * Lossless for all basic Zod types. Logs a warning for unsupported features.
 */
export function translateZodToGemini(toolName, schema) {
    const warnings = [];
    const shape = schema.shape;
    const properties = {};
    const required = [];
    for (const [key, fieldSchema] of Object.entries(shape)) {
        const translated = translateGeminiZodField(fieldSchema, warnings);
        properties[key] = translated;
        // A field is required unless it is ZodOptional or ZodDefault at the top level
        const isOptional = fieldSchema instanceof z.ZodOptional || fieldSchema instanceof z.ZodDefault;
        if (!isOptional) {
            required.push(key);
        }
    }
    const geminiParameterSchema = {
        type: 'object',
        properties,
        ...(required.length > 0 ? { required } : {}),
    };
    // Extract top-level description from the Zod schema if present
    const description = schema.description;
    if (description) {
        geminiParameterSchema.description = description;
    }
    return {
        planToolName: toolName,
        geminiFunctionName: toolName,
        geminiParameterSchema,
        lossless: warnings.length === 0,
        warnings,
    };
}
/**
 * Translate a Gemini function-call result back to a plain object that matches
 * Planu's Zod schema expectations. This is a thin pass-through: Gemini sends
 * JSON-compatible values, which are already valid for Zod parsing.
 */
export function translateGeminiResultToPlanu(result) {
    // Gemini returns JSON-compatible objects — no structural transformation needed.
    // Future versions may handle type coercion for edge cases (e.g., number-as-string).
    return result;
}
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
function unwrapOptional(schema) {
    if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable) {
        return schema.unwrap();
    }
    if (schema instanceof z.ZodDefault) {
        return schema.def.innerType;
    }
    return schema;
}
function translateGeminiZodField(schema, warnings) {
    // Unwrap Optional/Nullable/Default wrappers
    const inner = unwrapOptional(schema);
    const description = schema.description;
    const base = translateZodCore(inner, warnings);
    if (description) {
        base.description = description;
    }
    return base;
}
/** Handle scalar primitive Zod types → Gemini schema property. */
function translateScalar(schema) {
    if (schema instanceof z.ZodString) {
        return { type: 'string' };
    }
    if (schema instanceof z.ZodNumber) {
        return { type: 'number' };
    }
    if (schema instanceof z.ZodBoolean) {
        return { type: 'boolean' };
    }
    if (schema instanceof z.ZodEnum) {
        return { type: 'string', enum: schema.options };
    }
    if (schema instanceof z.ZodLiteral) {
        const val = schema.value;
        const type = typeof val === 'number' ? 'number' : typeof val === 'boolean' ? 'boolean' : 'string';
        return { type, enum: [String(val)] };
    }
    return null;
}
/** Handle composite Zod types (array, object). */
function translateComposite(schema, warnings) {
    if (schema instanceof z.ZodArray) {
        const items = translateGeminiZodField(schema.element, warnings);
        return { type: 'array', items };
    }
    if (schema instanceof z.ZodObject) {
        return translateNestedObject(schema, warnings);
    }
    return null;
}
function translateNestedObject(schema, warnings) {
    const shape = schema.shape;
    const properties = {};
    const required = [];
    for (const [key, fieldSchema] of Object.entries(shape)) {
        properties[key] = translateGeminiZodField(fieldSchema, warnings);
        const isOptional = fieldSchema instanceof z.ZodOptional || fieldSchema instanceof z.ZodDefault;
        if (!isOptional) {
            required.push(key);
        }
    }
    return {
        type: 'object',
        properties,
        ...(required.length > 0 ? { required } : {}),
    };
}
function translateZodCore(schema, warnings) {
    const scalar = translateScalar(schema);
    if (scalar) {
        return scalar;
    }
    const composite = translateComposite(schema, warnings);
    if (composite) {
        return composite;
    }
    if (schema instanceof z.ZodUnion || schema instanceof z.ZodDiscriminatedUnion) {
        warnings.push('ZodUnion found — translated to string (Gemini does not support union types)');
        return { type: 'string' };
    }
    if (schema instanceof z.ZodRecord) {
        warnings.push('ZodRecord found — translated to generic object (no property constraints)');
        return { type: 'object', properties: {} };
    }
    // Unknown/unsupported Zod type — fall back to string
    warnings.push(`Unsupported Zod type ${schema.constructor.name} — translated to string`);
    return { type: 'string' };
}
//# sourceMappingURL=tool-schema-translator.js.map