import { IDE } from "../.."
import { AutocompleteCodeSnippet, AutocompleteSnippetType, AutocompleteStaticSnippet } from "../types"
import { HelperVars } from "../util/HelperVars"

import { ImportDefinitionsService } from "./ImportDefinitionsService"
import { getSymbolsForSnippet } from "./ranking"
import { RootPathContextService } from "./root-path-context/RootPathContextService"
import { StaticContextService } from "./static-context/StaticContextService"

export class ContextRetrievalService {
  private importDefinitionsService: ImportDefinitionsService
  private rootPathContextService: RootPathContextService
  private staticContextService: StaticContextService

  constructor(private readonly ide: IDE) {
    this.importDefinitionsService = new ImportDefinitionsService(this.ide)
    this.rootPathContextService = new RootPathContextService(this.importDefinitionsService, this.ide)
    this.staticContextService = new StaticContextService(this.ide)
  }

  public async getSnippetsFromImportDefinitions(helper: HelperVars): Promise<AutocompleteCodeSnippet[]> {
    if (helper.options.useImports === false) {
      return []
    }

    const importSnippets: AutocompleteCodeSnippet[] = []
    const fileInfo = this.importDefinitionsService.get(helper.filepath)
    if (fileInfo) {
      const { imports } = fileInfo
      // Look for imports of any symbols around the current range
      const textAroundCursor =
        helper.fullPrefix.split("\n").slice(-5).join("\n") + helper.fullSuffix.split("\n").slice(0, 3).join("\n")
      const symbols = Array.from(getSymbolsForSnippet(textAroundCursor)).filter(
        (symbol) => !helper.lang.topLevelKeywords.includes(symbol),
      )
      for (const symbol of symbols) {
        const rifs = imports[symbol]
        if (Array.isArray(rifs)) {
          const snippets: AutocompleteCodeSnippet[] = rifs.map((rif) => {
            return {
              filepath: rif.filepath,
              content: rif.contents,
              type: AutocompleteSnippetType.Code,
            }
          })

          importSnippets.push(...snippets)
        }
      }
    }

    return importSnippets
  }

  public async getRootPathSnippets(helper: HelperVars): Promise<AutocompleteCodeSnippet[]> {
    if (!helper.treePath) {
      return []
    }

    return this.rootPathContextService.getContextForPath(helper.filepath, helper.treePath)
  }

  public async getStaticContextSnippets(helper: HelperVars): Promise<AutocompleteStaticSnippet[]> {
    return this.staticContextService.getContext(helper)
  }

  public dispose(): void {
    this.importDefinitionsService.dispose()
  }

  /**
   * Initialize the import definitions cache for a file.
   * This is normally done automatically when the active text editor changes,
   * but needs to be called manually when using context fetching outside the normal flow.
   */
  public async initializeForFile(filepath: string): Promise<void> {
    try {
      await this.importDefinitionsService.cache.initKey(filepath)
    } catch (e) {
      console.warn(`Failed to initialize import definitions cache for ${filepath}:`, e)
    }
  }
}
