/**
 * Schema Visitor - Minimal abstraction over raw msgpack schema
 *
 * Philosophy:
 *   - Keep raw schema structure
 *   - Resolve type references into a graph
 *   - No normalization - languages handle their own conventions
 *   - Output is "compiled schema" with resolved types
 */
/**
 * SchemaVisitor - Walks raw msgpack schema and resolves references
 */
export class SchemaVisitor {
    structs = new Map();
    responses = new Map();
    visit(commandsSchema, responsesSchema) {
        // Reset state
        this.structs.clear();
        this.responses.clear();
        const commands = [];
        // Schema format: ["named_union", [[name, schema], ...]]
        const commandPairs = commandsSchema[1];
        const responsePairs = responsesSchema[1];
        // First, visit all response types (including ErrorResponse)
        for (const [respName, respSchema] of responsePairs) {
            if (typeof respSchema !== 'string') {
                const respStruct = this.visitStruct(respName, respSchema);
                this.responses.set(respName, respStruct);
            }
        }
        // Visit all commands and pair with responses
        for (let i = 0; i < commandPairs.length; i++) {
            const [cmdName, cmdSchema] = commandPairs[i];
            // Find matching response (skip ErrorResponse which is always last)
            const normalResponses = responsePairs.filter(([name]) => name !== 'ErrorResponse');
            const [respName] = normalResponses[i];
            // Discover command structure
            const cmdStruct = this.visitStruct(cmdName, cmdSchema);
            this.structs.set(cmdName, cmdStruct);
            // Create command mapping
            commands.push({
                name: cmdName,
                fields: cmdStruct.fields,
                responseType: respName,
            });
        }
        return {
            structs: this.structs,
            commands,
            responses: this.responses,
        };
    }
    visitStruct(name, schema) {
        const fields = [];
        // Schema is an object with __typename and fields
        for (const [key, value] of Object.entries(schema)) {
            if (key === '__typename')
                continue;
            fields.push({
                name: key,
                type: this.visitType(value),
            });
        }
        return { name, fields };
    }
    visitType(schema) {
        // Primitive string type
        if (typeof schema === 'string') {
            return this.resolvePrimitive(schema);
        }
        // Array type descriptor: ['vector', [elementType]]
        if (Array.isArray(schema)) {
            const [kind, args] = schema;
            switch (kind) {
                case 'vector': {
                    const [elemType] = args;
                    // Special case: vector<unsigned char> = bytes
                    if (elemType === 'unsigned char') {
                        return { kind: 'primitive', primitive: 'bytes' };
                    }
                    return {
                        kind: 'vector',
                        element: this.visitType(elemType),
                    };
                }
                case 'array': {
                    const [elemType, size] = args;
                    // Special case: array<unsigned char, N> = bytes
                    if (elemType === 'unsigned char') {
                        return { kind: 'primitive', primitive: 'bytes' };
                    }
                    return {
                        kind: 'array',
                        element: this.visitType(elemType),
                        size,
                    };
                }
                case 'optional': {
                    const [elemType] = args;
                    return {
                        kind: 'optional',
                        element: this.visitType(elemType),
                    };
                }
                case 'shared_ptr': {
                    // Dereference shared_ptr - just use inner type
                    const [innerType] = args;
                    return this.visitType(innerType);
                }
                case 'alias': {
                    // Alias types (like uint256_t) are treated as bytes
                    return { kind: 'primitive', primitive: 'bytes' };
                }
                default:
                    throw new Error(`Unknown type kind: ${kind}`);
            }
        }
        // Inline struct definition
        if (typeof schema === 'object' && schema.__typename) {
            const structName = schema.__typename;
            // Check if already visited
            if (!this.structs.has(structName)) {
                const struct = this.visitStruct(structName, schema);
                this.structs.set(structName, struct);
            }
            return {
                kind: 'struct',
                struct: this.structs.get(structName),
            };
        }
        throw new Error(`Cannot resolve type: ${JSON.stringify(schema)}`);
    }
    resolvePrimitive(name) {
        const primitiveMap = {
            'bool': 'bool',
            'int': 'u32',
            'unsigned int': 'u32',
            'unsigned short': 'u16',
            'unsigned long': 'u64',
            'unsigned char': 'u8',
            'double': 'f64',
            'string': 'string',
            'bin32': 'bytes',
            'field2': 'field2', // Extension field (Fq2) - pair of field elements
        };
        const primitive = primitiveMap[name];
        if (primitive) {
            return { kind: 'primitive', primitive };
        }
        // Unknown primitive - treat as struct reference
        // This will be resolved later if it's a real struct
        return {
            kind: 'struct',
            struct: { name, fields: [] }, // Placeholder
        };
    }
}
//# sourceMappingURL=data:application/json;base64, 