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

export class JavaIndexer extends BaseIndexer {
  public readonly language = 'java';

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

    const addExport = (name: string, type: SymbolType, node: Node) => {
      exports.push({
        name,
        type,
        filePath,
        line: node.startPosition.row + 1,
        column: node.startPosition.column + 1,
        parameters: this.extractParameters(node)
      });
    };

    // 1. Classes
    const classNodes = root.descendantsOfType('class_declaration');
    for (const node of classNodes) {
        const nameNode = node.childForFieldName('name');
        if (nameNode) addExport(nameNode.text, 'class', 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 pak.age.Class;
    const importNodes = root.descendantsOfType('import_declaration');
    for (const node of importNodes) {
        const nameNode = node.children.find(c => c.type === 'scoped_identifier' || c.type === 'identifier');
        if (nameNode) {
            const fullPath = nameNode.text;
            const parts = fullPath.split('.');
            const localName = 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('method_invocation');

    for (const node of callNodes) {
        const nameNode = node.childForFieldName('name');
        if (nameNode) {
            const name = nameNode.text;
            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 formalParams = paramNode.descendantsOfType('formal_parameter');
        for (const p of formalParams) {
            const nameNode = p.childForFieldName('name');
            if (nameNode) params.push(nameNode.text);
        }
    }
    return params;
  }
}
