import { Node } from 'web-tree-sitter';
import { BaseIndexer } from './base-indexer.js';
import { ExportMetadata, SymbolType } from '@scandiumsys/owstra-types';

export class GoIndexer extends BaseIndexer {
  public readonly language = 'go';

  public extractExports(root: Node, filePath: string): ExportMetadata[] {
    const exports: ExportMetadata[] = [];

    const addExport = (name: string, type: SymbolType, node: Node) => {
      // In Go, symbols are exported if they start with an uppercase letter
      if (name && /^[A-Z]/.test(name)) {
        exports.push({
          name,
          type,
          filePath,
          line: node.startPosition.row + 1,
          column: node.startPosition.column + 1,
          parameters: this.extractParameters(node)
        });
      }
    };

    // 1. Functions
    const funcNodes = root.descendantsOfType('function_declaration');
    for (const node of funcNodes) {
        const nameNode = node.childForFieldName('name');
        if (nameNode) addExport(nameNode.text, 'function', node);
    }

    // 2. Methods
    const methodNodes = root.descendantsOfType('method_declaration');
    for (const node of methodNodes) {
        const nameNode = node.childForFieldName('name');
        if (nameNode) addExport(nameNode.text, 'method', node);
    }

    return exports;
  }

  public extractImports(root: Node): Record<string, string> {
    const imports: Record<string, string> = {};

    // import "path/to/pkg"
    const importNodes = root.descendantsOfType('import_spec');
    for (const node of importNodes) {
        const pathNode = node.childForFieldName('path');
        if (pathNode) {
            const fullPath = pathNode.text.replace(/"/g, '');
            const parts = fullPath.split('/');
            const localName = node.childForFieldName('name')?.text || parts[parts.length - 1];
            if (localName) imports[localName] = fullPath;
        }
    }

    return imports;
  }

  public extractCalls(root: Node): Array<{ name: string, argPositions: Array<{ row: number; column: number }> }> {
    const calls: Array<{ name: string, argPositions: Array<{ row: number; column: number }> }> = [];
    const callNodes = root.descendantsOfType('call_expression');

    for (const node of callNodes) {
        const funcNode = node.childForFieldName('function');
        if (funcNode) {
            let name = funcNode.text;
            if (funcNode.type === 'selector_expression') {
                name = funcNode.childForFieldName('field')?.text || name;
            }

            const argsNode = node.childForFieldName('arguments');
            const argPositions: Array<{ row: number; column: number }> = [];
            if (argsNode) {
                for (let i = 0; i < argsNode.childCount; i++) {
                    const arg = argsNode.child(i);
                    if (arg && arg.isNamed && arg.text !== '(' && arg.text !== ')') {
                        argPositions.push({
                            row: arg.startPosition.row,
                            column: arg.startPosition.column
                        });
                    }
                }
            }
            calls.push({ name, argPositions });
        }
    }

    return calls;
  }

  private extractParameters(node: Node): string[] {
    const params: string[] = [];
    const paramNode = node.childForFieldName('parameters');
    if (paramNode) {
        const parameterDeclarations = paramNode.descendantsOfType('parameter_declaration');
        for (const p of parameterDeclarations) {
            const nameNodes = p.children.filter(c => c.type === 'identifier');
            for (const nameNode of nameNodes) {
                params.push(nameNode.text);
            }
        }
    }
    return params;
  }
}
