// codragraph/src/core/ingestion/method-extractors/configs/go.ts
// Verified against tree-sitter-go 0.23.4
import { SupportedLanguages } from '../../../../_shared/index.js';
import { extractSimpleTypeName } from '../../type-extractors/shared.js';
// ---------------------------------------------------------------------------
// Go helpers
// ---------------------------------------------------------------------------
/**
 * Extract the method/function name.
 * - method_declaration: name is a `field_identifier`
 * - function_declaration: name is an `identifier`
 */
function extractGoName(node) {
    const nameNode = node.childForFieldName('name');
    return nameNode?.text;
}
/**
 * Extract return type from the `result` field.
 *
 * Go supports single return (`int`) and multi-return (`(User, error)`).
 * Multi-return appears as a `parameter_list` — extract the first type.
 */
function extractGoReturnType(node) {
    const result = node.childForFieldName('result');
    if (!result)
        return undefined;
    // Single return type (type_identifier, pointer_type, etc.)
    if (result.type !== 'parameter_list') {
        return result.text?.trim();
    }
    // Multi-return: (Type, error) — extract first parameter's type
    for (let i = 0; i < result.namedChildCount; i++) {
        const param = result.namedChild(i);
        if (param?.type === 'parameter_declaration') {
            const typeNode = param.childForFieldName('type');
            if (typeNode)
                return typeNode.text?.trim();
        }
    }
    return undefined;
}
/**
 * Extract parameters from the `parameters` field.
 *
 * Go parameter_list contains parameter_declaration nodes with optional
 * `name` and required `type` fields. Go allows multiple names for one type:
 * `func(a, b int)` — each name shares the type.
 *
 * Handles variadic_parameter_declaration (`...string`).
 */
function extractGoParameters(node) {
    const paramList = node.childForFieldName('parameters');
    if (!paramList)
        return [];
    const params = [];
    for (let i = 0; i < paramList.namedChildCount; i++) {
        const param = paramList.namedChild(i);
        if (!param)
            continue;
        if (param.type === 'parameter_declaration') {
            const typeNode = param.childForFieldName('type');
            const typeName = typeNode
                ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
                : null;
            // Go allows multiple names for one type: func(a, b int)
            const names = [];
            for (let j = 0; j < param.namedChildCount; j++) {
                const child = param.namedChild(j);
                if (child?.type === 'identifier') {
                    names.push(child.text);
                }
            }
            const rawType = typeNode?.text?.trim() ?? null;
            if (names.length === 0) {
                // Unnamed parameter: func(int, string)
                params.push({
                    name: `_${i}`,
                    type: typeName,
                    rawType,
                    isOptional: false,
                    isVariadic: false,
                });
            }
            else {
                for (const name of names) {
                    params.push({ name, type: typeName, rawType, isOptional: false, isVariadic: false });
                }
            }
        }
        else if (param.type === 'variadic_parameter_declaration') {
            const nameNode = param.childForFieldName('name');
            const typeNode = param.childForFieldName('type');
            const typeName = typeNode
                ? (extractSimpleTypeName(typeNode) ?? typeNode.text?.trim() ?? null)
                : null;
            params.push({
                name: nameNode?.text ?? `_${i}`,
                type: typeName,
                rawType: typeNode?.text?.trim() ?? null,
                isOptional: false,
                isVariadic: true,
            });
        }
    }
    return params;
}
/**
 * Go visibility: uppercase first character = exported (public), lowercase = unexported (private).
 */
function extractGoVisibility(node) {
    const name = extractGoName(node);
    if (!name || name.length === 0)
        return 'private';
    const first = name[0];
    return first === first.toUpperCase() && first !== first.toLowerCase() ? 'public' : 'private';
}
/**
 * Extract receiver type from the `receiver` field.
 *
 * The receiver is a parameter_list with one parameter_declaration:
 *   (r *Repo) → pointer_type → type_identifier "Repo"
 *   (r Repo)  → type_identifier "Repo"
 */
function extractGoReceiverType(node) {
    const receiver = node.childForFieldName('receiver');
    if (!receiver)
        return undefined;
    for (let i = 0; i < receiver.namedChildCount; i++) {
        const param = receiver.namedChild(i);
        if (param?.type === 'parameter_declaration') {
            const typeNode = param.childForFieldName('type');
            if (!typeNode)
                continue;
            // Unwrap pointer_type: *User → User
            const inner = typeNode.type === 'pointer_type' ? typeNode.firstNamedChild : typeNode;
            return inner?.text;
        }
    }
    return undefined;
}
/**
 * Resolve owner name from the receiver type.
 * For function_declaration (no receiver), returns undefined.
 */
function extractGoOwnerName(node) {
    return extractGoReceiverType(node);
}
// ---------------------------------------------------------------------------
// Config
// ---------------------------------------------------------------------------
export const goMethodConfig = {
    language: SupportedLanguages.Go,
    // Each method_declaration/function_declaration is treated as its own "container"
    // for extractFromNode() — not used with extract() in the traditional sense.
    // method_elem covers interface method signatures (abstract methods).
    typeDeclarationNodes: ['method_declaration', 'function_declaration', 'method_elem'],
    methodNodeTypes: ['method_declaration', 'function_declaration', 'method_elem'],
    bodyNodeTypes: [],
    extractName: extractGoName,
    extractReturnType: extractGoReturnType,
    extractParameters: extractGoParameters,
    extractVisibility: extractGoVisibility,
    extractReceiverType: extractGoReceiverType,
    extractOwnerName: extractGoOwnerName,
    isStatic(node) {
        // Go functions (no receiver) are effectively static
        return node.type === 'function_declaration';
    },
    isAbstract(node, _ownerNode) {
        // Go interface method signatures (method_elem) are abstract — no body
        return node.type === 'method_elem';
    },
    isFinal(_node) {
        return false; // Go has no final methods
    },
};
