import * as vscode from "vscode";
import { Logger } from "../utils";

export class NavigationService {
  private logger: Logger;

  constructor() {
    this.logger = new Logger("Codeflash Navigation");
  }

  async navigateToFunction(
    functionName: string,
    fileUri: vscode.Uri,
  ): Promise<void> {
    const document = await vscode.workspace.openTextDocument(fileUri);
    const editor = await vscode.window.showTextDocument(document);
    this.fallbackFindTheFunctionInFile(functionName, fileUri, editor);

    // Get all symbols in this document
    // const symbols = await vscode.commands.executeCommand<
    //   vscode.DocumentSymbol[]
    // >("vscode.executeDocumentSymbolProvider", fileUri);

    // if (!symbols) {
    //   this.fallbackFindTheFunctionInFile(functionName, fileUri, editor);
    //   return;
    // }

    // let target: vscode.DocumentSymbol | undefined;

    // if (functionName.includes(".")) {
    //   const [cls, method] = functionName.split(".");
    //   const classSymbol = symbols.find(
    //     (s) => s.name === cls && s.kind === vscode.SymbolKind.Class,
    //   );
    //   if (classSymbol) {
    //     target = classSymbol.children.find(
    //       (s) => s.name === method && s.kind === vscode.SymbolKind.Function,
    //     );
    //   }
    // } else {
    //   target = symbols.find(
    //     (s) => s.name === functionName && s.kind === vscode.SymbolKind.Function,
    //   );
    // }

    // if (target) {
    //   const range = target.selectionRange;
    //   editor.revealRange(range, vscode.TextEditorRevealType.InCenter);
    //   editor.selection = new vscode.Selection(range.start, range.start);
    // } else {
    //   this.fallbackFindTheFunctionInFile(functionName, fileUri, editor);
    // }
  }

  async fallbackFindTheFunctionInFile(
    functionName: string,
    fileUri: vscode.Uri,
    editor: vscode.TextEditor,
  ) {
    const pos = await this.manuallyFindTheFunctionInFile(functionName, fileUri);
    if (!pos) {
      return;
    }
    const range = new vscode.Range(pos, pos);
    editor.revealRange(range, vscode.TextEditorRevealType.InCenter);
    editor.selection = new vscode.Selection(range.start, range.start);
  }

  async manuallyFindTheFunctionInFile(
    functionName: string,
    uri: vscode.Uri,
  ): Promise<vscode.Position | null> {
    const document = await vscode.workspace.openTextDocument(uri);

    const text = document.getText();
    let position: vscode.Position | null = null;

    if (functionName.includes(".")) {
      // Class method
      const [className, methodName] = functionName.split(".");

      // Find class
      const classRegex = new RegExp(`^\\s*class\\s+${className}\\b.*:`, "m");
      const classMatch = classRegex.exec(text);
      if (classMatch) {
        const classStart = classMatch.index + classMatch[0].length;
        const classBody = text.substring(classStart);

        // Find method inside class body
        const methodRegex = new RegExp(
          `^[ \\t]+(?:async\\s+)?def\\s+${methodName}\\s*\\(`,
          "m",
        );
        const methodMatch = methodRegex.exec(classBody);
        if (methodMatch) {
          const absoluteIndex = classStart + methodMatch.index;
          position = document.positionAt(absoluteIndex);
        }
      }
    } else {
      // Top-level function
      const funcRegex = new RegExp(
        `^(?:async\\s+)?def\\s+${functionName}\\s*\\(`,
        "m",
      );
      const match = funcRegex.exec(text);
      if (match) {
        position = document.positionAt(match.index);
      }
    }

    if (position) {
      return position;
    }
    return null;
  }

  async navigateToFunctionOld(
    functionName: string,
    uri: vscode.Uri,
  ): Promise<void> {
    try {
      this.logger.debug(
        `Navigating to function '${functionName}' in file: ${uri.fsPath}`,
      );

      await vscode.workspace.fs.stat(uri);
      const doc = await vscode.workspace.openTextDocument(uri);
      const editor = await vscode.window.showTextDocument(doc);

      const position = await this.findFunctionPosition(doc, functionName);
      if (position) {
        editor.selection = new vscode.Selection(position, position);
        editor.revealRange(
          new vscode.Range(position, position),
          vscode.TextEditorRevealType.InCenter,
        );
      } else {
        vscode.window.showWarningMessage(
          `Function '${functionName}' not found in ${uri.fsPath}.`,
        );
      }
    } catch (error) {
      const errorMessage =
        error instanceof Error ? error.message : String(error);
      this.logger.error(
        `Error navigating to function: ${errorMessage}`,
        error instanceof Error ? error : undefined,
      );
      vscode.window.showErrorMessage(
        `Error navigating to function: ${errorMessage}`,
      );
    }
  }

  private async findFunctionPosition(
    doc: vscode.TextDocument,
    functionName: string,
  ): Promise<vscode.Position | null> {
    const text = doc.getText();

    // Try to use document symbols first (more accurate)
    try {
      const symbols = await vscode.commands.executeCommand<
        vscode.DocumentSymbol[]
      >("vscode.executeDocumentSymbolProvider", doc.uri);

      if (symbols) {
        const functionSymbol = this.findSymbol(symbols, functionName);
        if (functionSymbol) {
          return functionSymbol.range.start;
        }
      }
    } catch (error) {
      this.logger.warn(`Failed to get document symbols: ${error}`);
    }

    // Fallback to text search
    return this.findFunctionByText(doc, text, functionName);
  }

  private findSymbol(
    symbols: vscode.DocumentSymbol[],
    fullName: string,
  ): vscode.DocumentSymbol | undefined {
    const parts = fullName.split(".");

    if (parts.length === 1) {
      return symbols.find(
        (s) => s.kind === vscode.SymbolKind.Function && s.name === parts[0],
      );
    } else if (parts.length === 2) {
      const [className, methodName] = parts;
      const classSymbol = symbols.find(
        (s) => s.kind === vscode.SymbolKind.Class && s.name === className,
      );

      if (classSymbol?.children) {
        return classSymbol.children.find(
          (s) => s.kind === vscode.SymbolKind.Method && s.name === methodName,
        );
      }
    }

    return undefined;
  }

  private findFunctionByText(
    doc: vscode.TextDocument,
    text: string,
    functionName: string,
  ): vscode.Position | null {
    let functionPosition = text.indexOf(`def ${functionName}`);

    // Handle class methods
    if (functionPosition === -1 && functionName.includes(".")) {
      const parts = functionName.split(".");
      if (parts.length === 2) {
        const className = parts[0];
        const methodName = parts[1];

        const classPosition = text.indexOf(`class ${className}`);
        if (classPosition !== -1) {
          const methodSearch = `def ${methodName}`;
          functionPosition = text.indexOf(methodSearch, classPosition);
        }
      }
    }

    // Fallback to just searching for the function name
    if (functionPosition === -1) {
      functionPosition = text.indexOf(functionName);
    }

    return functionPosition !== -1 ? doc.positionAt(functionPosition) : null;
  }

  dispose(): void {
    this.logger.dispose();
  }
}
