import { Uri, window } from "vscode";
import { CodeQLCliServer } from "../codeql-cli/cli";
import { QueryRunner } from "../query-server";
import { basename, join } from "path";
import { getErrorMessage } from "../pure/helpers-pure";
import { redactableError } from "../pure/errors";
import { AppCommandManager, QueryEditorCommands } from "../common/commands";
import { showAndLogExceptionWithTelemetry } from "../common/vscode/log";

type QueryEditorOptions = {
  commandManager: AppCommandManager;

  queryRunner: QueryRunner;
  cliServer: CodeQLCliServer;

  qhelpTmpDir: string;
};

export function getQueryEditorCommands({
  commandManager,
  queryRunner,
  cliServer,
  qhelpTmpDir,
}: QueryEditorOptions): QueryEditorCommands {
  const openReferencedFileCommand = async (selectedQuery: Uri) =>
    await openReferencedFile(queryRunner, cliServer, selectedQuery);

  return {
    "codeQL.openReferencedFile": openReferencedFileCommand,
    // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command
    "codeQL.openReferencedFileContextEditor": openReferencedFileCommand,
    // Since we are tracking extension usage through commands, this command mirrors the "codeQL.openReferencedFile" command
    "codeQL.openReferencedFileContextExplorer": openReferencedFileCommand,
    "codeQL.previewQueryHelp": async (selectedQuery: Uri) =>
      await previewQueryHelp(
        commandManager,
        cliServer,
        qhelpTmpDir,
        selectedQuery,
      ),
    "codeQL.previewQueryHelpContextEditor": async (selectedQuery: Uri) =>
      await previewQueryHelp(
        commandManager,
        cliServer,
        qhelpTmpDir,
        selectedQuery,
      ),
    "codeQL.previewQueryHelpContextExplorer": async (selectedQuery: Uri) =>
      await previewQueryHelp(
        commandManager,
        cliServer,
        qhelpTmpDir,
        selectedQuery,
      ),
  };
}

async function previewQueryHelp(
  commandManager: AppCommandManager,
  cliServer: CodeQLCliServer,
  qhelpTmpDir: string,
  selectedQuery: Uri,
): Promise<void> {
  // selectedQuery is unpopulated when executing through the command palette
  const pathToQhelp = selectedQuery
    ? selectedQuery.fsPath
    : window.activeTextEditor?.document.uri.fsPath;
  if (pathToQhelp) {
    // Create temporary directory
    const relativePathToMd = `${basename(pathToQhelp, ".qhelp")}.md`;
    const absolutePathToMd = join(qhelpTmpDir, relativePathToMd);
    const uri = Uri.file(absolutePathToMd);
    try {
      await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd);
      await commandManager.execute("markdown.showPreviewToSide", uri);
    } catch (e) {
      const errorMessage = getErrorMessage(e).includes(
        "Generating qhelp in markdown",
      )
        ? redactableError`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.`
        : redactableError`Could not open a preview of the generated file (${absolutePathToMd}).`;
      void showAndLogExceptionWithTelemetry(errorMessage, {
        fullMessage: `${errorMessage}\n${getErrorMessage(e)}`,
      });
    }
  }
}

async function openReferencedFile(
  qs: QueryRunner,
  cliServer: CodeQLCliServer,
  selectedQuery: Uri,
): Promise<void> {
  // If no file is selected, the path of the file in the editor is selected
  const path =
    selectedQuery?.fsPath || window.activeTextEditor?.document.uri.fsPath;
  if (qs !== undefined && path) {
    const resolved = await cliServer.resolveQlref(path);
    const uri = Uri.file(resolved.resolvedPath);
    await window.showTextDocument(uri, { preview: false });
  }
}
