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

export class SwiftIndexer extends BaseIndexer {
  public readonly language = 'swift';

  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. Functions
    const funcNodes = root.descendantsOfType('function_declaration');
    for (const node of funcNodes) {
        const nameNode = node.childForFieldName('name');
        if (nameNode) addExport(nameNode.text, 'function', node);
    }

    return exports;
  }

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

    // import Module
    const importNodes = root.descendantsOfType('import_declaration');
    for (const node of importNodes) {
        const pathNode = node.children.find(c => c.type === 'import_path');
        if (pathNode) {
            const fullPath = pathNode.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('call_expression');

    for (const node of callNodes) {
        // In Swift, the function name is often in a simple_identifier within the call
        const funcNode = node.children[0];
        if (funcNode) {
            const name = funcNode.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 pNodes = paramNode.descendantsOfType('parameter');
        for (const p of pNodes) {
            const nameNode = p.childForFieldName('name') || p.childForFieldName('external_name');
            if (nameNode) params.push(nameNode.text);
        }
    }
    return params;
  }
}
