/* eslint-disable @typescript-eslint/no-explicit-any */
import { StructuredError } from '@agentuity/core';
import { validator as honoValidator } from 'hono/validator';
import { validateSchema, formatValidationIssues } from './_validation';
/**
 * Create a route validator middleware with input and/or output validation.
 *
 * Automatically handles different validation targets based on HTTP method:
 * - GET requests: validates query parameters (if input schema provided)
 * - POST/PUT/PATCH/DELETE: validates JSON body (if input schema provided)
 * - All methods: validates JSON response (if output schema provided)
 *
 * @param options - Validation configuration
 * @param options.input - Input schema (query params for GET, body for POST/PUT/PATCH/DELETE)
 * @param options.output - Output schema for response validation
 * @returns Hono middleware handler
 *
 * @example GET with query validation
 * ```typescript
 * import { validator } from '@agentuity/runtime';
 *
 * router.get('/search',
 *   validator({
 *     input: z.object({ q: z.string(), limit: z.number().optional() }),
 *     output: z.array(SearchResultSchema)
 *   }),
 *   async (c) => {
 *     const { q, limit } = c.req.valid('query'); // Typed!
 *     const results = await search(q, limit);
 *     return c.json(results);
 *   }
 * );
 * ```
 *
 * @example POST with body validation
 * ```typescript
 * router.post('/users',
 *   validator({
 *     input: z.object({ name: z.string() }),
 *     output: UserSchema
 *   }),
 *   async (c) => {
 *     const data = c.req.valid('json'); // Typed!
 *     const user = await createUser(data);
 *     return c.json(user);
 *   }
 * );
 * ```
 */
export const validator = ((options) => {
    const { input: inputSchema, output: outputSchema, stream } = options;
    // Helper to build input validator that detects HTTP method
    const buildInputValidator = (schema) => {
        return async (c, next) => {
            const method = c.req.method.toUpperCase();
            // GET requests validate query parameters
            if (method === 'GET') {
                const queryValidator = honoValidator('query', async (value, c) => {
                    const result = await validateSchema(schema, value);
                    if (!result.success) {
                        return c.json({
                            error: 'Validation failed',
                            message: formatValidationIssues(result.issues),
                            issues: result.issues,
                        }, 400);
                    }
                    return result.data;
                });
                return await queryValidator(c, next);
            }
            // POST/PUT/PATCH/DELETE validate JSON body
            const jsonValidator = honoValidator('json', async (value, c) => {
                const result = await validateSchema(schema, value);
                if (!result.success) {
                    return c.json({
                        error: 'Validation failed',
                        message: formatValidationIssues(result.issues),
                        issues: result.issues,
                    }, 400);
                }
                return result.data;
            });
            return await jsonValidator(c, next);
        };
    };
    // Output validation middleware (runs after handler)
    const outputValidator = async (c, next) => {
        await next();
        if (!outputSchema)
            return;
        // Skip output validation for streaming routes
        if (stream)
            return;
        const res = c.res;
        if (!res)
            return;
        // Only validate JSON responses
        const contentType = res.headers.get('Content-Type') ?? '';
        if (!contentType.toLowerCase().includes('application/json')) {
            return;
        }
        // Clone so we don't consume the body that will be sent
        let responseBody;
        try {
            const cloned = res.clone();
            responseBody = await cloned.json();
        }
        catch {
            const OutputValidationError = StructuredError('OutputValidationError')();
            throw new OutputValidationError({
                message: 'Output validation failed: response is not valid JSON',
                issues: [],
            });
        }
        const result = await validateSchema(outputSchema, responseBody);
        if (!result.success) {
            const OutputValidationError = StructuredError('OutputValidationError')();
            throw new OutputValidationError({
                message: `Output validation failed: ${formatValidationIssues(result.issues)}`,
                issues: result.issues,
            });
        }
        // Replace response with validated/sanitized JSON
        c.res = new Response(JSON.stringify(result.data), {
            status: res.status,
            headers: res.headers,
        });
    };
    // If no input schema, only do output validation
    if (!inputSchema) {
        return outputValidator;
    }
    // If no output schema, only do input validation
    if (!outputSchema) {
        return buildInputValidator(inputSchema);
    }
    // Compose: input validator → output validator
    const inputMiddleware = buildInputValidator(inputSchema);
    const composed = async (c, next) => {
        // Run input validator first, then output validator, then handler
        const result = await inputMiddleware(c, async () => {
            await outputValidator(c, next);
        });
        // If inputMiddleware returned early (validation failed), return that response
        return result;
    };
    return composed;
});
//# sourceMappingURL=validator.js.map