/**
 * GraphQL Schema Parser
 * 
 * Parses GraphQL SDL (Schema Definition Language) files into our internal types.
 * Uses the graphql-js library for parsing.
 */ import { buildSchema, isObjectType, isInputObjectType, isEnumType, isInterfaceType, isUnionType, isScalarType, isNonNullType, isListType, isNamedType, getNamedType } from 'graphql';
// ============================================================================
// Type Conversion Helpers
// ============================================================================
/**
 * Convert a GraphQL type to our type reference format
 */ function convertTypeToRef(type) {
    if (isNonNullType(type)) {
        return {
            kind: 'NON_NULL',
            name: null,
            ofType: convertTypeToRef(type.ofType)
        };
    }
    if (isListType(type)) {
        return {
            kind: 'LIST',
            name: null,
            ofType: convertTypeToRef(type.ofType)
        };
    }
    if (isNamedType(type)) {
        const namedType = getNamedType(type);
        let kind = 'SCALAR';
        if (isObjectType(namedType)) kind = 'OBJECT';
        else if (isInputObjectType(namedType)) kind = 'INPUT_OBJECT';
        else if (isEnumType(namedType)) kind = 'ENUM';
        else if (isInterfaceType(namedType)) kind = 'INTERFACE';
        else if (isUnionType(namedType)) kind = 'UNION';
        else if (isScalarType(namedType)) kind = 'SCALAR';
        return {
            kind,
            name: namedType.name,
            ofType: null
        };
    }
    return {
        kind: 'SCALAR',
        name: 'Unknown',
        ofType: null
    };
}
/**
 * Convert GraphQL argument to our format
 */ function convertArgument(arg) {
    return {
        name: arg.name,
        description: arg.description || null,
        type: convertTypeToRef(arg.type),
        defaultValue: arg.defaultValue !== undefined ? JSON.stringify(arg.defaultValue) : null,
        isRequired: isNonNullType(arg.type)
    };
}
/**
 * Convert GraphQL input field to our format
 */ function convertInputField(field) {
    return {
        name: field.name,
        description: field.description || null,
        type: convertTypeToRef(field.type),
        defaultValue: field.defaultValue !== undefined ? JSON.stringify(field.defaultValue) : null,
        isRequired: isNonNullType(field.type)
    };
}
/**
 * Convert GraphQL field to our format
 */ function convertField(field) {
    return {
        name: field.name,
        description: field.description || null,
        args: field.args.map(convertArgument),
        type: convertTypeToRef(field.type),
        isDeprecated: field.deprecationReason != null,
        deprecationReason: field.deprecationReason || null
    };
}
// ============================================================================
// Type Definition Converters
// ============================================================================
/**
 * Convert an object type to our format
 */ function convertObjectType(type) {
    const fields = type.getFields();
    return {
        kind: 'OBJECT',
        name: type.name,
        description: type.description || null,
        fields: Object.values(fields).map(convertField),
        interfaces: type.getInterfaces().map((i)=>i.name)
    };
}
/**
 * Convert an input object type to our format
 */ function convertInputObjectType(type) {
    const fields = type.getFields();
    return {
        kind: 'INPUT_OBJECT',
        name: type.name,
        description: type.description || null,
        inputFields: Object.values(fields).map(convertInputField)
    };
}
/**
 * Convert an enum type to our format
 */ function convertEnumType(type) {
    return {
        kind: 'ENUM',
        name: type.name,
        description: type.description || null,
        enumValues: type.getValues().map((v)=>({
                name: v.name,
                description: v.description || null,
                isDeprecated: v.deprecationReason != null,
                deprecationReason: v.deprecationReason || null
            }))
    };
}
/**
 * Convert an interface type to our format
 */ function convertInterfaceType(type, schema) {
    const fields = type.getFields();
    const implementations = schema.getPossibleTypes(type);
    return {
        kind: 'INTERFACE',
        name: type.name,
        description: type.description || null,
        fields: Object.values(fields).map(convertField),
        possibleTypes: implementations.map((t)=>t.name)
    };
}
/**
 * Convert a union type to our format
 */ function convertUnionType(type) {
    return {
        kind: 'UNION',
        name: type.name,
        description: type.description || null,
        possibleTypes: type.getTypes().map((t)=>t.name)
    };
}
/**
 * Convert a scalar type to our format
 */ function convertScalarType(type) {
    return {
        kind: 'SCALAR',
        name: type.name,
        description: type.description || null
    };
}
// ============================================================================
// Operation Extractors
// ============================================================================
/**
 * Extract operations from a root type (Query, Mutation, Subscription)
 */ function extractOperations(rootType, operationType) {
    if (!rootType) return [];
    const fields = rootType.getFields();
    return Object.values(fields).map((field)=>({
            id: `${operationType}-${field.name}`.toLowerCase(),
            name: field.name,
            description: field.description || null,
            operationType,
            args: field.args.map(convertArgument),
            returnType: convertTypeToRef(field.type),
            isDeprecated: field.deprecationReason != null,
            deprecationReason: field.deprecationReason || null
        }));
}
/**
 * Extract directives from schema
 */ function extractDirectives(schema) {
    return schema.getDirectives().map((directive)=>({
            name: directive.name,
            description: directive.description || null,
            locations: directive.locations,
            args: directive.args.map(convertArgument)
        }));
}
// ============================================================================
// Main Parser Functions
// ============================================================================
/**
 * Parse a GraphQL SDL string into our schema format
 */ export function parseGraphQLSchema(sdl) {
    // Build the schema from SDL
    const schema = buildSchema(sdl);
    return convertGraphQLSchema(schema);
}
/**
 * Convert a graphql-js schema object to our format
 */ export function convertGraphQLSchema(schema) {
    const typeMap = schema.getTypeMap();
    const types = {};
    // Convert all types (excluding built-in types that start with __)
    for (const [name, type] of Object.entries(typeMap)){
        if (name.startsWith('__')) continue; // Skip introspection types
        if (isObjectType(type)) {
            types[name] = convertObjectType(type);
        } else if (isInputObjectType(type)) {
            types[name] = convertInputObjectType(type);
        } else if (isEnumType(type)) {
            types[name] = convertEnumType(type);
        } else if (isInterfaceType(type)) {
            types[name] = convertInterfaceType(type, schema);
        } else if (isUnionType(type)) {
            types[name] = convertUnionType(type);
        } else if (isScalarType(type)) {
            types[name] = convertScalarType(type);
        }
    }
    // Get root types
    const queryType = schema.getQueryType();
    const mutationType = schema.getMutationType();
    const subscriptionType = schema.getSubscriptionType();
    // Schema info
    const info = {
        description: schema.description || null,
        queryType: queryType?.name || null,
        mutationType: mutationType?.name || null,
        subscriptionType: subscriptionType?.name || null
    };
    return {
        info,
        types,
        directives: extractDirectives(schema),
        queries: extractOperations(queryType, 'query'),
        mutations: extractOperations(mutationType, 'mutation'),
        subscriptions: extractOperations(subscriptionType, 'subscription')
    };
}
/**
 * Parse GraphQL SDL from a file content (handles both .graphql and .gql)
 */ export async function parseGraphQLFile(content) {
    return parseGraphQLSchema(content);
}
/**
 * Validate that content is valid GraphQL SDL
 */ export function validateGraphQLSchema(sdl) {
    try {
        buildSchema(sdl);
        return {
            valid: true
        };
    } catch (error) {
        return {
            valid: false,
            error: error instanceof Error ? error.message : 'Invalid GraphQL schema'
        };
    }
}
/**
 * Parse introspection query result to our schema format
 */ export function parseIntrospectionResult(introspectionResult) {
    // The introspection result contains __schema with types, directives, etc.
    // We need to convert this to our format
    // For now, this is a placeholder - full implementation would parse the introspection JSON
    const result = introspectionResult;
    if (!result.__schema) {
        throw new Error('Invalid introspection result: missing __schema');
    }
    // This is a simplified implementation
    // A full implementation would parse all the introspection data
    const schema = {
        info: {
            description: null,
            queryType: result.__schema.queryType?.name || null,
            mutationType: result.__schema.mutationType?.name || null,
            subscriptionType: result.__schema.subscriptionType?.name || null
        },
        types: {},
        directives: [],
        queries: [],
        mutations: [],
        subscriptions: []
    };
    return schema;
}
// ============================================================================
// Query Generation Helpers
// ============================================================================
/**
 * Generate a sample query string for an operation
 */ export function generateOperationQuery(operation) {
    const operationKeyword = operation.operationType;
    const args = operation.args.map((arg)=>`$${arg.name}: ${formatTypeRefForQuery(arg.type)}`).join(', ');
    const fieldArgs = operation.args.map((arg)=>`${arg.name}: $${arg.name}`).join(', ');
    const argsStr = args ? `(${args})` : '';
    const fieldArgsStr = fieldArgs ? `(${fieldArgs})` : '';
    return `${operationKeyword} ${operation.name}${argsStr} {
  ${operation.name}${fieldArgsStr} {
    # Add fields here
  }
}`;
}
/**
 * Format type ref for query variables
 */ function formatTypeRefForQuery(typeRef) {
    if (typeRef.kind === 'NON_NULL' && typeRef.ofType) {
        return `${formatTypeRefForQuery(typeRef.ofType)}!`;
    }
    if (typeRef.kind === 'LIST' && typeRef.ofType) {
        return `[${formatTypeRefForQuery(typeRef.ofType)}]`;
    }
    return typeRef.name || 'Unknown';
}
/**
 * Generate example variables for an operation
 */ export function generateExampleVariables(operation) {
    const variables = {};
    for (const arg of operation.args){
        variables[arg.name] = generateExampleValue(arg.type);
    }
    return variables;
}
/**
 * Generate example value for a type
 */ function generateExampleValue(typeRef) {
    // Unwrap non-null
    if (typeRef.kind === 'NON_NULL' && typeRef.ofType) {
        return generateExampleValue(typeRef.ofType);
    }
    // Handle list
    if (typeRef.kind === 'LIST' && typeRef.ofType) {
        return [
            generateExampleValue(typeRef.ofType)
        ];
    }
    // Handle named types
    const typeName = typeRef.name;
    switch(typeName){
        case 'String':
            return 'example';
        case 'Int':
            return 42;
        case 'Float':
            return 3.14;
        case 'Boolean':
            return true;
        case 'ID':
            return 'abc123';
        default:
            // For custom types, return an empty object as placeholder
            return {};
    }
}
