/*
 * Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
 * @generated-id: b65a1bd4c0e9
 */
// Not needed if lax mode
import * as z from "zod/v4";
import { isUnknown as isDiscriminatedUnionUnknown } from "./discriminatedUnion.js";
import { RFCDate } from "./rfcdate.js";
import { startCountingUnrecognized } from "./unrecognized.js";
/**
 * Smart union parser that tries all schemas and returns the best match
 * based on the number of populated fields.
 */
export function smartUnion(options) {
    return z.unknown().transform((input, ctx) => {
        const candidates = [];
        const errors = options.map(() => []);
        const parentUnrecognizedCtr = startCountingUnrecognized();
        // Filter out invalid options
        for (const [i, option] of options.entries()) {
            const unrecognizedCtr = startCountingUnrecognized();
            const result = option.safeParse(input);
            const inexactCount = unrecognizedCtr.end();
            const zeroDefaultCount = 0;
            if (result.success) {
                candidates.push({
                    data: result.data,
                    inexactCount,
                    zeroDefaultCount,
                    fieldCount: -1, // We'll count this later if needed
                });
                continue;
            }
            errors[i].push(...result.error.issues);
        }
        // No valid options
        if (candidates.length === 0) {
            parentUnrecognizedCtr.end(0);
            ctx.addIssue({ input: input, code: "invalid_union", errors: errors });
            return z.NEVER;
        }
        let best = candidates[0];
        // Find the best option
        for (const candidate of candidates) {
            // Minor optimization to avoid counting fields if there's only one candidate
            if (candidates.length > 1) {
                candidate.fieldCount = countFieldsRecursive(candidate.data);
            }
            best = better(candidate, best);
        }
        // The cost of this union should be the cost of the best candidate not all the candidates
        parentUnrecognizedCtr.end(best.inexactCount);
        return best.data;
    });
}
function better(a, b) {
    // First prefer exact matches over inexact ones
    const aIsExact = a.inexactCount === 0;
    const bIsExact = b.inexactCount === 0;
    if (aIsExact !== bIsExact) {
        return aIsExact ? a : b;
    }
    // Then compare field counts
    const actualFieldCountA = a.fieldCount - a.zeroDefaultCount;
    const actualFieldCountB = b.fieldCount - b.zeroDefaultCount;
    if (actualFieldCountA !== actualFieldCountB) {
        return actualFieldCountA > actualFieldCountB ? a : b;
    }
    return a.inexactCount < b.inexactCount ? a : b;
}
/**
 * Counts the number of fields in a parsed value recursively.
 * @param `parsed` assumed to *not* contain cycles
 * fieldCount: total number of fields found
 * inexactCount: number of primitive values that are not unrecognized enum values
 */
function countFieldsRecursive(parsed) {
    let fieldCount = 0;
    const queue = [parsed];
    let index = 0;
    while (index < queue.length) {
        const value = queue[index++];
        if (value === undefined || isDiscriminatedUnionUnknown(value)) {
            continue;
        }
        // Check if it's a primitive value
        const type = typeof value;
        if (value === null
            || type === "number"
            || type === "string"
            || type === "boolean"
            || type === "bigint"
            || value instanceof Date
            || value instanceof RFCDate) {
            fieldCount++;
            continue;
        }
        // Handle arrays
        if (Array.isArray(value)) {
            queue.push(...value);
            continue;
        }
        // Handle objects
        if (type === "object") {
            queue.push(...Object.values(value));
        }
    }
    return fieldCount;
}
//# sourceMappingURL=smartUnion.js.map